mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-07-04 22:54:43 +02:00
Compare commits
30 Commits
7.5.2
...
feat/range
Author | SHA1 | Date | |
---|---|---|---|
5a100ef988 | |||
711fba0b2a | |||
671a27fa6f | |||
03de685dc4 | |||
f616885206 | |||
7da4eb1ab5 | |||
629646ab06 | |||
74a1a1f954 | |||
aa44078018 | |||
bfbf406418 | |||
2accedf264 | |||
6ef0d58480 | |||
fbf4a638b4 | |||
9abfa21078 | |||
b84599b4b3 | |||
058983cdd5 | |||
6ba3694121 | |||
8e8e31b80e | |||
da2e66c1f8 | |||
d5d6fcb859 | |||
96f73331f9 | |||
020947d90c | |||
7dbd0bcff8 | |||
9626302f04 | |||
1b4a347e8b | |||
19e6ed4b9b | |||
6b1b0f2d6a | |||
e499bc02ec | |||
62084fffdd | |||
d012f79349 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -29,18 +29,18 @@ jobs:
|
||||
fi
|
||||
- name: Publish Release
|
||||
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
|
||||
run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
|
||||
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
|
||||
- name: Publish Snapshot
|
||||
if: ${{ runner.os == 'Linux' && env.STATUS != 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
run: ./gradlew publishToSonatype
|
||||
run: ./gradlew publishAllPublicationsToMavenCentralRepository
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PASSWORD }}
|
||||
- name: Publish core javadoc
|
||||
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
uses: cpina/github-action-push-to-another-repository@main
|
||||
|
@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
repositories {
|
||||
maven {
|
||||
name = "PlaceholderAPI"
|
||||
url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||
url = uri("https://repo.extendedclip.com/releases/")
|
||||
}
|
||||
|
||||
maven {
|
||||
|
@ -252,6 +252,11 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
return Bukkit.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String serverBrand() {
|
||||
return Bukkit.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
public void onEnable() {
|
||||
|
@ -22,12 +22,20 @@ import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Singleton;
|
||||
import com.plotsquared.bukkit.permissions.BukkitPermissionHandler;
|
||||
import com.plotsquared.bukkit.permissions.BukkitRangedPermissionResolver;
|
||||
import com.plotsquared.bukkit.permissions.LuckPermsRangedPermissionResolver;
|
||||
import com.plotsquared.bukkit.permissions.VaultPermissionHandler;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.permissions.PermissionHandler;
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class PermissionModule extends AbstractModule {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PermissionModule.class.getSimpleName());
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
PermissionHandler providePermissionHandler() {
|
||||
@ -40,4 +48,18 @@ public class PermissionModule extends AbstractModule {
|
||||
return new BukkitPermissionHandler();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
RangedPermissionResolver provideRangedPermissionResolver() {
|
||||
if (Settings.Permissions.USE_LUCKPERMS_RANGE_RESOLVER) {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
|
||||
LOGGER.info("Using experimental LuckPerms ranged permission resolver");
|
||||
return new LuckPermsRangedPermissionResolver();
|
||||
}
|
||||
LOGGER.warn("Enabled LuckPerms ranged permission resolver, but LuckPerms is not installed. " +
|
||||
"Falling back to default Bukkit ranged permission resolver");
|
||||
}
|
||||
return new BukkitRangedPermissionResolver();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import com.plotsquared.core.plot.flag.implementations.CopperOxideFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.MiscInteractFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.SculkSensorInteractFlag;
|
||||
import com.plotsquared.core.util.PlotFlagUtil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
@ -42,31 +41,11 @@ import org.bukkit.event.block.BlockReceiveGameEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class BlockEventListener117 implements Listener {
|
||||
|
||||
private static final Set<Material> COPPER_OXIDIZING = Set.of(
|
||||
Material.COPPER_BLOCK,
|
||||
Material.EXPOSED_COPPER,
|
||||
Material.WEATHERED_COPPER,
|
||||
Material.OXIDIZED_COPPER,
|
||||
Material.CUT_COPPER,
|
||||
Material.EXPOSED_CUT_COPPER,
|
||||
Material.WEATHERED_CUT_COPPER,
|
||||
Material.OXIDIZED_CUT_COPPER,
|
||||
Material.CUT_COPPER_STAIRS,
|
||||
Material.EXPOSED_CUT_COPPER_STAIRS,
|
||||
Material.WEATHERED_CUT_COPPER_STAIRS,
|
||||
Material.OXIDIZED_CUT_COPPER_STAIRS,
|
||||
Material.CUT_COPPER_SLAB,
|
||||
Material.EXPOSED_CUT_COPPER_SLAB,
|
||||
Material.WEATHERED_CUT_COPPER_SLAB,
|
||||
Material.OXIDIZED_CUT_COPPER_SLAB
|
||||
);
|
||||
|
||||
@Inject
|
||||
public BlockEventListener117() {
|
||||
}
|
||||
@ -184,7 +163,7 @@ public class BlockEventListener117 implements Listener {
|
||||
if (plot == null) {
|
||||
return;
|
||||
}
|
||||
if (COPPER_OXIDIZING.contains(event.getNewState().getType())) {
|
||||
if (event.getNewState().getType().name().contains("COPPER")) {
|
||||
if (!plot.getFlag(CopperOxideFlag.class)) {
|
||||
plot.debug("Copper could not oxide because copper-oxide = false");
|
||||
event.setCancelled(true);
|
||||
|
@ -29,6 +29,7 @@ import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
|
||||
import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent;
|
||||
import com.google.inject.Inject;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.Command;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
@ -38,6 +39,7 @@ import com.plotsquared.core.permissions.Permission;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.PlotAreaType;
|
||||
import com.plotsquared.core.plot.flag.FlagContainer;
|
||||
import com.plotsquared.core.plot.flag.implementations.BeaconEffectsFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
|
||||
@ -48,6 +50,7 @@ import com.plotsquared.core.plot.flag.types.BooleanFlag;
|
||||
import com.plotsquared.core.plot.world.PlotAreaManager;
|
||||
import com.plotsquared.core.util.PlotFlagUtil;
|
||||
import io.papermc.paper.event.entity.EntityMoveEvent;
|
||||
import io.papermc.paper.event.world.StructuresLocateEvent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
@ -458,6 +461,21 @@ public class PaperListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't let the server die when populating cartographers (villager offering maps) in classic plot worlds
|
||||
* (as those don't generate POIs)
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onStructuresLocate(StructuresLocateEvent event) {
|
||||
if (!PlotSquared.get().getPlotAreaManager().hasPlotArea(event.getWorld().getName())) {
|
||||
return;
|
||||
}
|
||||
final PlotArea area = PlotSquared.get().getPlotAreaManager().getPlotAreaByString(event.getWorld().getName());
|
||||
if (area != null && area.getType() == PlotAreaType.NORMAL) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getBooleanFlagValue(
|
||||
@NonNull FlagContainer container,
|
||||
@NonNull Class<? extends BooleanFlag<?>> flagClass,
|
||||
|
@ -88,10 +88,8 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Boat;
|
||||
@ -600,7 +598,11 @@ public class PlayerEventListener implements Listener {
|
||||
// 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)))) {
|
||||
plotListener.plotEntry(pp, plot);
|
||||
// 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)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} else {
|
||||
pp.sendMessage(
|
||||
TranslatableCaption.of("deny.no_enter"),
|
||||
@ -1370,22 +1372,7 @@ public class PlayerEventListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBucketEmpty(PlayerBucketEmptyEvent event) {
|
||||
BlockFace bf = event.getBlockFace();
|
||||
// Note: a month after Bukkit 1.14.4 released, they added the API method
|
||||
// PlayerBucketEmptyEvent#getBlock(), which returns the block the
|
||||
// bucket contents is going to be placed at. Currently we determine this
|
||||
// block ourselves to retain compatibility with 1.13.
|
||||
final Block block;
|
||||
// if the block can be waterlogged, the event might waterlog the block
|
||||
// sometimes
|
||||
if (event.getBlockClicked().getBlockData() instanceof Waterlogged waterlogged
|
||||
&& !waterlogged.isWaterlogged() && event.getBucket() != Material.LAVA_BUCKET) {
|
||||
block = event.getBlockClicked();
|
||||
} else {
|
||||
block = event.getBlockClicked().getLocation()
|
||||
.add(bf.getModX(), bf.getModY(), bf.getModZ())
|
||||
.getBlock();
|
||||
}
|
||||
final Block block = event.getBlock();
|
||||
Location location = BukkitUtil.adapt(block.getLocation());
|
||||
PlotArea area = location.getPlotArea();
|
||||
if (area == null) {
|
||||
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.bukkit.permissions;
|
||||
|
||||
import com.plotsquared.bukkit.player.BukkitPlayer;
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.MathMan;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class BukkitRangedPermissionResolver implements RangedPermissionResolver {
|
||||
|
||||
private static boolean CHECK_EFFECTIVE = true;
|
||||
|
||||
@Override
|
||||
public @NonNegative int getPermissionRange(
|
||||
final @NonNull PlotPlayer<?> generic,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
if (!(generic instanceof BukkitPlayer player)) {
|
||||
throw new IllegalArgumentException("PlotPlayer is not a BukkitPlayer");
|
||||
}
|
||||
if (hasWildcardRange(player, stub, worldContext)) {
|
||||
return INFINITE_RANGE_VALUE;
|
||||
}
|
||||
int max = 0;
|
||||
if (CHECK_EFFECTIVE) {
|
||||
boolean hasAny = false;
|
||||
String stubPlus = stub + ".";
|
||||
final Set<PermissionAttachmentInfo> effective = player.getPlatformPlayer().getEffectivePermissions();
|
||||
if (!effective.isEmpty()) {
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
// Ignore all "false" permissions
|
||||
if (!attach.getValue()) {
|
||||
continue;
|
||||
}
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith(stubPlus)) {
|
||||
hasAny = true;
|
||||
String end = permStr.substring(stubPlus.length());
|
||||
if (MathMan.isInteger(end)) {
|
||||
int val = Integer.parseInt(end);
|
||||
if (val > range) {
|
||||
return val;
|
||||
}
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasAny) {
|
||||
return max;
|
||||
}
|
||||
// Workaround
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith("plots.") && !permStr.equals("plots.use")) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
CHECK_EFFECTIVE = false;
|
||||
}
|
||||
}
|
||||
for (int i = range; i > 0; i--) {
|
||||
if (player.hasPermission(worldContext, stub + "." + i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull IntStream streamFullPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
return IntStream.of(getPermissionRange(player, stub, worldContext, range));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.bukkit.permissions;
|
||||
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.MathMan;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.node.types.PermissionNode;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class LuckPermsRangedPermissionResolver implements RangedPermissionResolver {
|
||||
|
||||
private final LuckPerms luckPerms;
|
||||
|
||||
public LuckPermsRangedPermissionResolver() {
|
||||
this.luckPerms = Objects.requireNonNull(
|
||||
Bukkit.getServicesManager().getRegistration(LuckPerms.class),
|
||||
"LuckPerms is not available"
|
||||
).getProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNegative int getPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
final @NonNegative int range
|
||||
) {
|
||||
// no need to use LuckPerms for basic checks
|
||||
if (this.hasWildcardRange(player, stub, worldContext)) {
|
||||
return INFINITE_RANGE_VALUE;
|
||||
}
|
||||
return this.streamFullPermissionRange(player, stub, worldContext, range)
|
||||
.sorted()
|
||||
.reduce((first, second) -> second)
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public IntStream streamFullPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
final User user = this.luckPerms.getUserManager().getUser(player.getUUID());
|
||||
if (user == null) {
|
||||
throw new IllegalStateException("Luckperms User is null - is the Player online? (UUID: %s)".formatted(player.getUUID()));
|
||||
}
|
||||
final QueryOptions queryOptions = worldContext == null ?
|
||||
QueryOptions.nonContextual() :
|
||||
QueryOptions.contextual(ImmutableContextSet.of("world", worldContext));
|
||||
return user.resolveInheritedNodes(queryOptions).stream()
|
||||
// only support normal permission nodes (regex permission nodes would be a pita to support)
|
||||
.filter(NodeType.PERMISSION::matches)
|
||||
.map(node -> ((PermissionNode) node).getPermission())
|
||||
// check that the node actually has additional data after the stub
|
||||
.filter(permission -> permission.startsWith(stub + "."))
|
||||
// extract the raw data after the stub
|
||||
.map(permission -> permission.substring(stub.length() + 1))
|
||||
// check if data is integer and parse
|
||||
.filter(MathMan::isInteger)
|
||||
.mapToInt(Integer::parseInt)
|
||||
// only use values that are positive
|
||||
.filter(value -> value > -1);
|
||||
}
|
||||
|
||||
}
|
@ -24,14 +24,12 @@ import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.events.TeleportCause;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.permissions.Permission;
|
||||
import com.plotsquared.core.permissions.PermissionHandler;
|
||||
import com.plotsquared.core.player.ConsolePlayer;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.PlotWeather;
|
||||
import com.plotsquared.core.plot.world.PlotAreaManager;
|
||||
import com.plotsquared.core.util.EventDispatcher;
|
||||
import com.plotsquared.core.util.MathMan;
|
||||
import com.plotsquared.core.util.WorldUtil;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
@ -47,13 +45,11 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.sk89q.worldedit.world.gamemode.GameModes.ADVENTURE;
|
||||
@ -150,77 +146,13 @@ public class BukkitPlayer extends PlotPlayer<Player> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringSplitter")
|
||||
@Override
|
||||
@NonNegative
|
||||
public int hasPermissionRange(
|
||||
final @NonNull String stub,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
if (hasPermission(Permission.PERMISSION_ADMIN.toString())) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
final String[] nodes = stub.split("\\.");
|
||||
final StringBuilder n = new StringBuilder();
|
||||
// Wildcard check from less specific permission to more specific permission
|
||||
for (int i = 0; i < (nodes.length - 1); i++) {
|
||||
n.append(nodes[i]).append(".");
|
||||
if (!stub.equals(n + Permission.PERMISSION_STAR.toString())) {
|
||||
if (hasPermission(n + Permission.PERMISSION_STAR.toString())) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wildcard check for the full permission
|
||||
if (hasPermission(stub + ".*")) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
// Permission value cache for iterative check
|
||||
int max = 0;
|
||||
if (CHECK_EFFECTIVE) {
|
||||
boolean hasAny = false;
|
||||
String stubPlus = stub + ".";
|
||||
final Set<PermissionAttachmentInfo> effective = player.getEffectivePermissions();
|
||||
if (!effective.isEmpty()) {
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
// Ignore all "false" permissions
|
||||
if (!attach.getValue()) {
|
||||
continue;
|
||||
}
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith(stubPlus)) {
|
||||
hasAny = true;
|
||||
String end = permStr.substring(stubPlus.length());
|
||||
if (MathMan.isInteger(end)) {
|
||||
int val = Integer.parseInt(end);
|
||||
if (val > range) {
|
||||
return val;
|
||||
}
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasAny) {
|
||||
return max;
|
||||
}
|
||||
// Workaround
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith("plots.") && !permStr.equals("plots.use")) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
CHECK_EFFECTIVE = false;
|
||||
}
|
||||
}
|
||||
for (int i = range; i > 0; i--) {
|
||||
if (hasPermission(stub + "." + i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
return PlotSquared.platform().rangedPermissionResolver().getPermissionRange(this, stub, null, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,6 +31,7 @@ import com.plotsquared.core.generator.IndependentPlotGenerator;
|
||||
import com.plotsquared.core.inject.annotations.DefaultGenerator;
|
||||
import com.plotsquared.core.location.World;
|
||||
import com.plotsquared.core.permissions.PermissionHandler;
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.expiration.ExpireManager;
|
||||
import com.plotsquared.core.plot.world.PlotAreaManager;
|
||||
@ -120,6 +121,14 @@ public interface PlotPlatform<P> extends LocaleHolder {
|
||||
*/
|
||||
@NonNull String serverImplementation();
|
||||
|
||||
/**
|
||||
* Gets the server brand name
|
||||
*
|
||||
* @return server brand
|
||||
* @since 7.5.3
|
||||
*/
|
||||
@NonNull String serverBrand();
|
||||
|
||||
/**
|
||||
* Gets the native server code package prefix.
|
||||
*
|
||||
@ -341,6 +350,10 @@ public interface PlotPlatform<P> extends LocaleHolder {
|
||||
return injector().getInstance(PermissionHandler.class);
|
||||
}
|
||||
|
||||
default @NonNull RangedPermissionResolver rangedPermissionResolver() {
|
||||
return injector().getInstance(RangedPermissionResolver.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ServicePipeline} implementation
|
||||
*
|
||||
|
@ -144,6 +144,7 @@ public class Buy extends Command {
|
||||
plot.getPlotModificationManager().setSign(player.getName());
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("working.claimed"),
|
||||
TagResolver.resolver("world", Tag.inserting(Component.text(plot.getArea().getWorldName()))),
|
||||
TagResolver.resolver("plot", Tag.inserting(Component.text(plot.getId().toString())))
|
||||
);
|
||||
this.eventDispatcher.callPostPlayerBuyPlot(player, previousOwner, plot, price);
|
||||
|
@ -131,6 +131,7 @@ public class Clear extends Command {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("working.clearing_done"),
|
||||
TagResolver.builder()
|
||||
.tag("world", Tag.inserting(Component.text(plot.getArea().getWorldName())))
|
||||
.tag("amount", Tag.inserting(Component.text(System.currentTimeMillis() - start)))
|
||||
.tag("plot", Tag.inserting(Component.text(plot.getId().toString())))
|
||||
.build()
|
||||
|
@ -24,6 +24,7 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -98,6 +99,14 @@ public enum CommandCategory implements Caption {
|
||||
return MiniMessage.miniMessage().deserialize(getComponent(localeHolder));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Component toComponent(
|
||||
@NonNull final LocaleHolder localeHolder,
|
||||
final @NonNull TagResolver @NonNull ... tagResolvers
|
||||
) {
|
||||
return MiniMessage.miniMessage().deserialize(getComponent(localeHolder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a player has access to this command category
|
||||
*
|
||||
|
@ -86,7 +86,8 @@ public class DebugPaste extends SubCommand {
|
||||
b.append("# WorldEdit implementation:\n");
|
||||
b.append(PlotSquared.platform().worldEditImplementations()).append("\n\n");
|
||||
b.append("# Server Information\n");
|
||||
b.append("Server Version: ").append(PlotSquared.platform().serverImplementation())
|
||||
b.append("Server Version: ").append(PlotSquared.platform().serverBrand()).append(": ")
|
||||
.append(PlotSquared.platform().serverImplementation()).append("\n")
|
||||
.append("\n");
|
||||
b.append("online_mode: ").append(!Settings.UUID.OFFLINE).append(';')
|
||||
.append(!Settings.UUID.OFFLINE).append('\n');
|
||||
|
@ -124,6 +124,7 @@ public class Delete extends SubCommand {
|
||||
"amount",
|
||||
Tag.inserting(Component.text(String.valueOf(System.currentTimeMillis() - start)))
|
||||
),
|
||||
TagResolver.resolver("world", Tag.inserting(Component.text(plotArea.getWorldName()))),
|
||||
TagResolver.resolver("plot", Tag.inserting(Component.text(plot.getId().toString())))
|
||||
);
|
||||
eventDispatcher.callPostDelete(plot);
|
||||
|
@ -113,38 +113,34 @@ public class Help extends Command {
|
||||
}
|
||||
if (cat == null && page == 0) {
|
||||
TextComponent.Builder builder = Component.text();
|
||||
builder.append(MINI_MESSAGE.deserialize(TranslatableCaption.of("help.help_header").getComponent(player)));
|
||||
builder.append(TranslatableCaption.of("help.help_header").toComponent(player));
|
||||
for (CommandCategory c : CommandCategory.values()) {
|
||||
if (!c.canAccess(player)) {
|
||||
continue;
|
||||
}
|
||||
builder.append(Component.newline()).append(MINI_MESSAGE
|
||||
.deserialize(
|
||||
TranslatableCaption.of("help.help_info_item").getComponent(player),
|
||||
TagResolver.builder()
|
||||
.tag("command", Tag.inserting(Component.text("/plot help")))
|
||||
.tag("category", Tag.inserting(Component.text(c.name().toLowerCase())))
|
||||
.tag("category_desc", Tag.inserting(c.toComponent(player)))
|
||||
.build()
|
||||
));
|
||||
builder.append(Component.newline());
|
||||
builder.append(TranslatableCaption.of("help.help_info_item").toComponent(
|
||||
player, TagResolver.builder()
|
||||
.tag("command", Tag.inserting(Component.text("/plot help")))
|
||||
.tag("category", Tag.inserting(Component.text(c.name().toLowerCase())))
|
||||
.tag("category_desc", Tag.inserting(c.toComponent(player)))
|
||||
.build()
|
||||
));
|
||||
}
|
||||
builder.append(Component.newline()).append(MINI_MESSAGE
|
||||
.deserialize(
|
||||
TranslatableCaption.of("help.help_info_item").getComponent(player),
|
||||
TagResolver.builder()
|
||||
.tag("command", Tag.inserting(Component.text("/plot help")))
|
||||
.tag("category", Tag.inserting(Component.text("all")))
|
||||
.tag(
|
||||
"category_desc",
|
||||
Tag.inserting(TranslatableCaption
|
||||
.of("help.help_display_all_commands")
|
||||
.toComponent(player))
|
||||
)
|
||||
.build()
|
||||
));
|
||||
builder.append(Component.newline()).append(MINI_MESSAGE.deserialize(TranslatableCaption
|
||||
.of("help.help_footer")
|
||||
.getComponent(player)));
|
||||
builder.append(Component.newline());
|
||||
builder.append(TranslatableCaption.of("help.help_info_item").toComponent(
|
||||
player, TagResolver.builder()
|
||||
.tag("command", Tag.inserting(Component.text("/plot help")))
|
||||
.tag("category", Tag.inserting(Component.text("all")))
|
||||
.tag(
|
||||
"category_desc", Tag.inserting(TranslatableCaption
|
||||
.of("help.help_display_all_commands")
|
||||
.toComponent(player))
|
||||
)
|
||||
.build()
|
||||
));
|
||||
builder.append(Component.newline());
|
||||
builder.append(TranslatableCaption.of("help.help_footer").toComponent(player));
|
||||
player.sendMessage(StaticCaption.of(MINI_MESSAGE.serialize(builder.asComponent())));
|
||||
return true;
|
||||
}
|
||||
|
@ -525,8 +525,8 @@ public class Settings extends Config {
|
||||
public static final class Limit {
|
||||
|
||||
@Comment("Should the limit be global (over multiple worlds)")
|
||||
public static boolean GLOBAL =
|
||||
false;
|
||||
public static boolean GLOBAL = false;
|
||||
|
||||
@Comment({"The max range of integer permissions to check for, e.g. 'plots.plot.127' or 'plots.set.flag.mob-cap.127'",
|
||||
"The value covers the permission range to check, you need to assign the permission to players/groups still",
|
||||
"Modifying the value does NOT change the amount of plots players can claim"})
|
||||
@ -737,6 +737,7 @@ public class Settings extends Config {
|
||||
|
||||
@Comment("If \"instabreak\" should consider the used tool.")
|
||||
public static boolean INSTABREAK_CONSIDER_TOOL = false;
|
||||
|
||||
}
|
||||
|
||||
@Comment({"Enable or disable parts of the plugin",
|
||||
@ -830,4 +831,17 @@ public class Settings extends Config {
|
||||
|
||||
}
|
||||
|
||||
@Comment({"Permission-Resolver specific settings"})
|
||||
public static final class Permissions {
|
||||
|
||||
@Comment({
|
||||
"use the new LuckPerms resolver for ranged permissions (e.g., plots.plot.<number>).",
|
||||
"in contrary to the default resolver, this resolver can handle inheritance of permissions.",
|
||||
"e.g. if the player has multiple matching permissions, for example, due to multiple group memberships " +
|
||||
"(plots.plot.5 & plots.plot.15), this resolver would use 15 as the limit as opposed to the previous 5."
|
||||
})
|
||||
public static boolean USE_LUCKPERMS_RANGE_RESOLVER = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package com.plotsquared.core.configuration.caption;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
@ -44,6 +45,16 @@ public interface Caption {
|
||||
*/
|
||||
@NonNull Component toComponent(@NonNull LocaleHolder localeHolder);
|
||||
|
||||
/**
|
||||
* Get the Adventure {@link ComponentLike} for this caption while applying custom {@link TagResolver}
|
||||
* (apart from the default {@code core.prefix})
|
||||
* @param localeHolder Local holder
|
||||
* @param tagResolvers custom tag resolvers to replace placeholders / parameters
|
||||
* @return {@link ComponentLike}
|
||||
* @since TODO
|
||||
*/
|
||||
@NonNull Component toComponent(@NonNull LocaleHolder localeHolder, @NonNull TagResolver @NonNull... tagResolvers);
|
||||
|
||||
@NonNull String toString();
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package com.plotsquared.core.configuration.caption;
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public final class StaticCaption implements Caption {
|
||||
@ -51,6 +52,14 @@ public final class StaticCaption implements Caption {
|
||||
return MiniMessage.miniMessage().deserialize(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Component toComponent(
|
||||
@NonNull final LocaleHolder localeHolder,
|
||||
final @NonNull TagResolver @NonNull ... tagResolvers
|
||||
) {
|
||||
return MiniMessage.miniMessage().deserialize(this.value, tagResolvers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return "StaticCaption(" + value + ")";
|
||||
|
@ -27,6 +27,7 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -96,13 +97,23 @@ public final class TranslatableCaption implements NamespacedCaption {
|
||||
|
||||
@Override
|
||||
public @NonNull Component toComponent(@NonNull final LocaleHolder localeHolder) {
|
||||
return this.toComponent(localeHolder, new TagResolver[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Component toComponent(
|
||||
@NonNull final LocaleHolder localeHolder,
|
||||
final @NonNull TagResolver @NonNull ... tagResolvers
|
||||
) {
|
||||
if (getKey().equals("core.prefix")) {
|
||||
return MiniMessage.miniMessage().deserialize(getComponent(localeHolder));
|
||||
}
|
||||
return MiniMessage.miniMessage().deserialize(getComponent(localeHolder), TagResolver.resolver(
|
||||
TagResolver[] finalResolvers = Arrays.copyOf(tagResolvers, tagResolvers.length + 1);
|
||||
finalResolvers[finalResolvers.length - 1] = TagResolver.resolver(
|
||||
"prefix",
|
||||
Tag.inserting(TranslatableCaption.of("core.prefix").toComponent(localeHolder))
|
||||
));
|
||||
);
|
||||
return MiniMessage.miniMessage().deserialize(getComponent(localeHolder), finalResolvers);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.permissions;
|
||||
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Represents a resolver for ranged permissions. Return values depend on the actual implementation (see Bukkit module).
|
||||
* <br>
|
||||
* Even though this interface is not linked to platform implementations by design, implementation-specific details are added to
|
||||
* the Javadocs.
|
||||
*
|
||||
* @since TODO
|
||||
*/
|
||||
public interface RangedPermissionResolver {
|
||||
|
||||
int INFINITE_RANGE_VALUE = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Gets the applicable range value of a player for a specific permission stub
|
||||
* ({@code plots.plot} would check for {@code plots.plot.<numeric>}).
|
||||
* <br>
|
||||
* The standard bukkit implementation would return the lowest numeric value, while the LuckPerms specific resolver would
|
||||
* try returning the highest possible value.
|
||||
*
|
||||
* @param player the permission holder
|
||||
* @param stub the permission stub to check against
|
||||
* @param worldContext the optional world context of the action requiring the range
|
||||
* @param range the maximum permission range to check against (for the default bukkit resolver)
|
||||
* @return the applicable range value of the player for the given permission stub
|
||||
* @since TODO
|
||||
*/
|
||||
@NonNegative
|
||||
int getPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
final @NonNegative int range
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a stream of all applicable permission range values for the given stub. The stream is unordered by default. If a
|
||||
* specific order is needed, use the stateful {@link IntStream#sorted()} operation.
|
||||
* <br>
|
||||
* The standard bukkit implementation will only return a stream containing a single value equal to
|
||||
* {@link #getPermissionRange(PlotPlayer, String, String, int)}. For LuckPerms, all applicable node values will be in the
|
||||
* stream.
|
||||
*
|
||||
* @param player the permission holder
|
||||
* @param stub the permission stub to check against
|
||||
* @param worldContext the optional world context of the action requiring the range
|
||||
* @param range the maximum permission range to check against (for the default bukkit resolver)
|
||||
* @return a stream of all applicable permission range values for the given stub
|
||||
* @since TODO
|
||||
*/
|
||||
@NonNull
|
||||
IntStream streamFullPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
final @NonNegative int range
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks if the given player has a wildcard range for the given permission stub.
|
||||
* <br>
|
||||
* For example, if checking for the stub {@code plots.plot}, this method would check for:
|
||||
* <ul>
|
||||
* <li>{@code *}</li>
|
||||
* <li>{@code plots.admin}</li>
|
||||
* <li>{@code plots.plot.*}</li>
|
||||
* <li>{@code plots.*}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param player the permission holder
|
||||
* @param stub the permission stub to check against
|
||||
* @param worldContext the optional world context of the action requiring the range
|
||||
* @return {@code true} if the player has a wildcard range for the given permission stub, else {@code false}
|
||||
* @since TODO
|
||||
*/
|
||||
default boolean hasWildcardRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext
|
||||
) {
|
||||
if (player.hasPermission(Permission.PERMISSION_STAR) ||
|
||||
player.hasPermission(Permission.PERMISSION_ADMIN) ||
|
||||
player.hasPermission(worldContext, stub + ".*")) {
|
||||
return true;
|
||||
}
|
||||
String node = stub;
|
||||
while (true) {
|
||||
int lastIndex = node.lastIndexOf('.');
|
||||
if (lastIndex == -1) {
|
||||
break;
|
||||
}
|
||||
node = node.substring(0, lastIndex);
|
||||
if (player.hasPermission(worldContext, node + ".*")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -444,7 +444,7 @@ public abstract class PlotPlayer<P> implements CommandCaller, OfflinePlotPlayer,
|
||||
|
||||
/**
|
||||
* Get this player's UUID.
|
||||
* === !IMPORTANT ===<br>
|
||||
* <p>=== !IMPORTANT ===</p>
|
||||
* The UUID is dependent on the mode chosen in the settings.yml and may not be the same as Bukkit has
|
||||
* (especially if using an old version of Bukkit that does not support UUIDs)
|
||||
*
|
||||
|
@ -1717,6 +1717,7 @@ public class Plot {
|
||||
}
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("working.claimed"),
|
||||
TagResolver.resolver("world", Tag.inserting(Component.text(this.getWorldName()))),
|
||||
TagResolver.resolver("plot", Tag.inserting(Component.text(this.getId().toString())))
|
||||
);
|
||||
if (teleport) {
|
||||
|
@ -25,30 +25,24 @@ import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HelpObject implements ComponentLike {
|
||||
|
||||
static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
|
||||
|
||||
private final Component rendered;
|
||||
|
||||
public HelpObject(final Command command, final String label, final PlotPlayer<?> audience) {
|
||||
rendered = MINI_MESSAGE.deserialize(
|
||||
TranslatableCaption.of("help.help_item").getComponent(audience),
|
||||
TagResolver.builder()
|
||||
.tag("usage", Tag.inserting(Component.text(command.getUsage().replace("{label}", label))))
|
||||
.tag("alias", Tag.inserting(Component.text(
|
||||
command.getAliases().isEmpty() ? "" : StringMan.join(command.getAliases(), " | ")
|
||||
)))
|
||||
.tag("desc", Tag.inserting(command.getDescription().toComponent(audience)))
|
||||
.tag("arguments", Tag.inserting(Component.text(buildArgumentList(command.getRequiredArguments()))))
|
||||
.tag("label", Tag.inserting(Component.text(label)))
|
||||
.build()
|
||||
);
|
||||
this.rendered = TranslatableCaption.of("help.help_item").toComponent(audience, TagResolver.builder()
|
||||
.tag("usage", Tag.inserting(Component.text(command.getUsage().replace("{label}", label))))
|
||||
.tag("alias", Tag.inserting(Component.text(
|
||||
command.getAliases().isEmpty() ? "" : StringMan.join(command.getAliases(), " | ")
|
||||
)))
|
||||
.tag("desc", Tag.inserting(command.getDescription().toComponent(audience)))
|
||||
.tag("arguments", Tag.inserting(Component.text(buildArgumentList(command.getRequiredArguments()))))
|
||||
.tag("label", Tag.inserting(Component.text(label)))
|
||||
.build());
|
||||
}
|
||||
|
||||
private String buildArgumentList(final Argument<?>[] arguments) {
|
||||
|
@ -390,11 +390,11 @@
|
||||
"info.area_list_tooltip": "<gold>Claimed=</gold><gray><claimed></gray>\n<gold>Usage=</gold><gray><usage></gray>\n<gold>Clusters=</gold><gray><clusters></gray>\n<gold>Region=</gold><gray><region></gray>\n<gold>Generator=</gold><gray><generator></gray>",
|
||||
"info.area_list_item": "<click:run_command:'<command_tp>'><hover:show_text:'<command_tp>'><dark_gray>[</dark_gray><gold><number></gold><dark_gray>]</dark_gray></hover></click> <click:run_command:'<command_info>'><hover:show_text:'<hover_info>'><gold><area_name></gold></hover></click><gray> - </gray><gray><area_type>:<area_terrain></gray>",
|
||||
"working.generating_component": "<prefix><gold>Started generating component from your settings.</gold>",
|
||||
"working.clearing_done": "<prefix><dark_aqua>Plot </dark_aqua><gold><plot></gold><dark_aqua> has been cleared! Took </dark_aqua><gold><amount>ms</gold><dark_aqua>.</dark_aqua>",
|
||||
"working.deleting_done": "<prefix><dark_aqua>Plot </dark_aqua><gold><plot></gold><dark_aqua> has been deleted! Took </dark_aqua><gold><amount>ms</gold><dark_aqua>.</dark_aqua>",
|
||||
"working.clearing_done": "<prefix><dark_aqua>Plot </dark_aqua><gold><world>;<plot></gold><dark_aqua> has been cleared! Took </dark_aqua><gold><amount>ms</gold><dark_aqua>.</dark_aqua>",
|
||||
"working.deleting_done": "<prefix><dark_aqua>Plot </dark_aqua><gold><world>;<plot></gold><dark_aqua> has been deleted! Took </dark_aqua><gold><amount>ms</gold><dark_aqua>.</dark_aqua>",
|
||||
"working.plot_not_claimed": "<prefix><gray>Plot not claimed.</gray>",
|
||||
"working.plot_is_claimed": "<prefix><gray>This plot is already claimed.</gray>",
|
||||
"working.claimed": "<prefix><dark_aqua>You successfully claimed the plot </dark_aqua><gold><plot></gold><dark_aqua>.</dark_aqua>",
|
||||
"working.claimed": "<prefix><dark_aqua>You successfully claimed the plot </dark_aqua><gold><world>;<plot></gold><dark_aqua>.</dark_aqua>",
|
||||
"working.progress": "<prefix><gray>Current progress: </gray><gold><progress></gold><gray>%</gray>",
|
||||
"working.component_complete": "<prefix><gold>Component generation has finished for plot <plot>.</gold>",
|
||||
"list.comment_list_header_paged": "<gray>(Page </gray><gold><cur></gold><gray>/</gray><gold><max></gold><gray>) </gray><gold>List of <amount> comment(s):</gold>",
|
||||
|
154
build.gradle.kts
154
build.gradle.kts
@ -1,5 +1,6 @@
|
||||
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
|
||||
@ -7,13 +8,12 @@ import java.net.URI
|
||||
plugins {
|
||||
java
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
signing
|
||||
|
||||
alias(libs.plugins.shadow)
|
||||
alias(libs.plugins.spotless)
|
||||
alias(libs.plugins.grgit)
|
||||
alias(libs.plugins.nexus)
|
||||
alias(libs.plugins.publish)
|
||||
|
||||
eclipse
|
||||
idea
|
||||
@ -22,7 +22,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.intellectualsites.plotsquared"
|
||||
version = "7.5.2"
|
||||
version = "7.5.4-SNAPSHOT"
|
||||
|
||||
if (!File("$rootDir/.git").exists()) {
|
||||
logger.lifecycle("""
|
||||
@ -41,16 +41,6 @@ subprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
name = "Sonatype OSS"
|
||||
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "Sonatype OSS (S01)"
|
||||
url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "Jitpack"
|
||||
url = uri("https://jitpack.io")
|
||||
@ -68,7 +58,7 @@ subprojects {
|
||||
apply {
|
||||
plugin<JavaPlugin>()
|
||||
plugin<JavaLibraryPlugin>()
|
||||
plugin<MavenPublishPlugin>()
|
||||
plugin<com.vanniktech.maven.publish.MavenPublishPlugin>()
|
||||
plugin<ShadowPlugin>()
|
||||
plugin<SpotlessPlugin>()
|
||||
plugin<SigningPlugin>()
|
||||
@ -79,8 +69,8 @@ subprojects {
|
||||
|
||||
dependencies {
|
||||
// Tests
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.12.1")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.12.1")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.13.0")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.13.0")
|
||||
}
|
||||
|
||||
plugins.withId("java") {
|
||||
@ -107,11 +97,6 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
val javaComponent = components["java"] as AdhocComponentWithVariants
|
||||
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) {
|
||||
skip()
|
||||
@ -127,66 +112,67 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
mavenPublishing {
|
||||
coordinates(
|
||||
groupId = "$group",
|
||||
artifactId = project.name,
|
||||
version = "${project.version}",
|
||||
)
|
||||
|
||||
pom {
|
||||
pom {
|
||||
name.set(project.name)
|
||||
description.set("PlotSquared, a land and world management plugin for Minecraft.")
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared")
|
||||
|
||||
name.set(project.name + " " + project.version)
|
||||
description.set("PlotSquared, a land and world management plugin for Minecraft.")
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared")
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set("GNU General Public License, Version 3.0")
|
||||
url.set("https://www.gnu.org/licenses/gpl-3.0.html")
|
||||
distribution.set("repo")
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id.set("Sauilitired")
|
||||
name.set("Alexander Söderberg")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
developer {
|
||||
id.set("NotMyFault")
|
||||
name.set("Alexander Brandes")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
email.set("contact(at)notmyfault.dev")
|
||||
}
|
||||
developer {
|
||||
id.set("SirYwell")
|
||||
name.set("Hannes Greule")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
developer {
|
||||
id.set("dordsor21")
|
||||
name.set("dordsor21")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared")
|
||||
connection.set("scm:git:https://github.com/IntellectualSites/PlotSquared.git")
|
||||
developerConnection.set("scm:git:git@github.com:IntellectualSites/PlotSquared.git")
|
||||
tag.set("${project.version}")
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system.set("GitHub")
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared/issues")
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name.set("GNU General Public License, Version 3.0")
|
||||
url.set("https://www.gnu.org/licenses/gpl-3.0.html")
|
||||
distribution.set("repo")
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id.set("Sauilitired")
|
||||
name.set("Alexander Söderberg")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
developer {
|
||||
id.set("NotMyFault")
|
||||
name.set("Alexander Brandes")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
email.set("contact(at)notmyfault.dev")
|
||||
}
|
||||
developer {
|
||||
id.set("SirYwell")
|
||||
name.set("Hannes Greule")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
developer {
|
||||
id.set("dordsor21")
|
||||
name.set("dordsor21")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared")
|
||||
connection.set("scm:git:https://github.com/IntellectualSites/PlotSquared.git")
|
||||
developerConnection.set("scm:git:git@github.com:IntellectualSites/PlotSquared.git")
|
||||
tag.set("${project.version}")
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system.set("GitHub")
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared/issues")
|
||||
}
|
||||
|
||||
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,7 +180,6 @@ subprojects {
|
||||
|
||||
compileJava {
|
||||
options.compilerArgs.add("-parameters")
|
||||
options.isDeprecation = true
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
@ -217,27 +202,18 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
nexusPublishing {
|
||||
this.repositories {
|
||||
sonatype {
|
||||
nexusUrl.set(URI.create("https://s01.oss.sonatype.org/service/local/"))
|
||||
snapshotRepositoryUrl.set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.getByName<Jar>("jar") {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
val supportedVersions = listOf("1.19.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4")
|
||||
val supportedVersions = listOf("1.19.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5")
|
||||
tasks {
|
||||
register("cacheLatestFaweArtifact") {
|
||||
val lastSuccessfulBuildUrl = uri("https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/api/json").toURL()
|
||||
val artifact = ((JsonSlurper().parse(lastSuccessfulBuildUrl) as Map<*, *>)["artifacts"] as List<*>)
|
||||
.map { it as Map<*, *> }
|
||||
.map { it["fileName"] as String }
|
||||
.first { it -> it.contains("Bukkit") }
|
||||
.first { it -> it.contains("Paper") }
|
||||
project.ext["faweArtifact"] = artifact
|
||||
}
|
||||
|
||||
|
@ -3,40 +3,40 @@
|
||||
paper = "1.20.4-R0.1-SNAPSHOT"
|
||||
guice = "7.0.0"
|
||||
spotbugs = "4.9.3"
|
||||
checkerqual = "3.49.2"
|
||||
checkerqual = "3.49.3"
|
||||
gson = "2.10"
|
||||
guava = "31.1-jre"
|
||||
snakeyaml = "2.0"
|
||||
adventure = "4.20.0"
|
||||
adventure-bukkit = "4.3.4"
|
||||
adventure = "4.21.0"
|
||||
adventure-bukkit = "4.4.0"
|
||||
log4j = "2.19.0"
|
||||
|
||||
# Plugins
|
||||
worldedit = "7.2.20"
|
||||
fawe = "2.13.0"
|
||||
placeholderapi = "2.11.6"
|
||||
luckperms = "5.4"
|
||||
essentialsx = "2.21.0"
|
||||
luckperms = "5.5"
|
||||
essentialsx = "2.21.1"
|
||||
mvdwapi = "3.1.1"
|
||||
|
||||
# Third party
|
||||
prtree = "2.0.1"
|
||||
aopalliance = "1.0"
|
||||
cloud-services = "1.8.4"
|
||||
arkitektonika = "2.1.3"
|
||||
arkitektonika = "2.1.4"
|
||||
squirrelid = "0.3.2"
|
||||
paster = "1.1.6"
|
||||
paster = "1.1.7"
|
||||
bstats = "3.1.0"
|
||||
paperlib = "1.0.8"
|
||||
informative-annotations = "1.5"
|
||||
informative-annotations = "1.6"
|
||||
vault = "1.7.1"
|
||||
serverlib = "2.3.6"
|
||||
serverlib = "2.3.7"
|
||||
|
||||
# Gradle plugins
|
||||
shadow = "8.3.6"
|
||||
grgit = "4.1.1"
|
||||
spotless = "7.0.2"
|
||||
nexus = "2.0.0"
|
||||
spotless = "7.0.4"
|
||||
publish = "0.32.0"
|
||||
runPaper = "2.3.1"
|
||||
|
||||
[libraries]
|
||||
@ -81,5 +81,5 @@ serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.re
|
||||
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
|
||||
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }
|
||||
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
|
||||
nexus = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus" }
|
||||
publish = { id = "com.vanniktech.maven.publish", version.ref = "publish" }
|
||||
runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" }
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
4
gradlew
vendored
4
gradlew
vendored
@ -114,7 +114,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@ -70,11 +70,11 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
Reference in New Issue
Block a user