Compare commits

..

13 Commits

101 changed files with 2362 additions and 1634 deletions

View File

@ -24,16 +24,20 @@ body:
- type: dropdown
attributes:
label: Server Version
description: Which server version are you using? If your server version is not listed, it is not supported. Update to a supported version first.
description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first.
multiple: false
options:
- '1.21.4'
- '1.21.3'
- '1.21.1'
- '1.20.6'
- '1.20.4'
- '1.20'
- '1.19.4'
- '1.19.3'
- '1.19.2'
- '1.19.1'
- '1.19'
- '1.18.2'
- '1.18.1'
- '1.17.1'
- '1.16.5'
validations:
required: true

View File

@ -1,7 +1,7 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"config:base",
":semanticCommitsDisabled"
],
"automerge": true,
@ -9,6 +9,7 @@
"dependencies"
],
"rebaseWhen": "conflicted",
"schedule": ["on the first day of the month"],
"ignoreDeps": [
"com.google.code.gson:gson",
"com.google.guava:guava",

View File

@ -11,11 +11,11 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v4
uses: gradle/wrapper-validation-action@v1
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
java-version: 17
- name: Clean Build
run: ./gradlew clean build

View File

@ -11,12 +11,12 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v4
uses: gradle/wrapper-validation-action@v1
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
java-version: 17
- name: Clean Build
run: ./gradlew clean build
- name: Determine release status
@ -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 publishAndReleaseToMavenCentral --no-configuration-cache
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_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 publishAllPublicationsToMavenCentralRepository
run: ./gradlew publishToSonatype
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_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

View File

@ -25,7 +25,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
java-version: 17
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Label conflicting PRs
uses: eps1lon/actions-label-merge-conflict@v3.0.3
uses: eps1lon/actions-label-merge-conflict@v2.1.0
with:
dirtyLabel: "unresolved-merge-conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -12,6 +12,6 @@ jobs:
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v6
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
repositories {
maven {
name = "PlaceholderAPI"
url = uri("https://repo.extendedclip.com/releases/")
url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}
maven {
@ -39,9 +39,7 @@ dependencies {
}
compileOnly(libs.placeholderapi)
compileOnly(libs.luckperms)
compileOnly(libs.essentialsx) {
exclude(group = "org.spigotmc")
}
compileOnly(libs.essentialsx)
compileOnly(libs.mvdwapi) { isTransitive = false }
// Other libraries
@ -55,6 +53,9 @@ dependencies {
// Adventure
implementation(libs.adventureBukkit)
// Cloud
implementation(libs.cloudPaper)
}
tasks.processResources {
@ -79,6 +80,7 @@ tasks.named<ShadowJar>("shadowJar") {
relocate("com.google.inject", "com.plotsquared.google")
relocate("org.aopalliance", "com.plotsquared.core.aopalliance")
relocate("cloud.commandframework.services", "com.plotsquared.core.services")
relocate("cloud.commandframework", "com.plotsquared.commands")
relocate("io.leangen.geantyref", "com.plotsquared.core.geantyref")
relocate("com.intellectualsites.arkitektonika", "com.plotsquared.core.arkitektonika")
relocate("com.intellectualsites.http", "com.plotsquared.core.http")
@ -103,18 +105,17 @@ tasks {
withType<Javadoc> {
val isRelease = if (rootProject.version.toString().endsWith("-SNAPSHOT")) "TODO" else rootProject.version.toString()
val opt = options as StandardJavadocDocletOptions
opt.links("https://jd.papermc.io/paper/1.20.4/")
opt.links("https://jd.papermc.io/paper/1.20/")
opt.links("https://docs.enginehub.org/javadoc/com.sk89q.worldedit/worldedit-bukkit/" + libs.worldeditBukkit.get().versionConstraint.toString())
opt.links("https://intellectualsites.github.io/plotsquared-javadocs/core/")
opt.links("https://jd.advntr.dev/api/" + libs.adventureApi.get().versionConstraint.toString())
opt.links("https://jd.advntr.dev/api/4.14.0/")
opt.links("https://google.github.io/guice/api-docs/" + libs.guice.get().versionConstraint.toString() + "/javadoc/")
opt.links("https://checkerframework.org/api/")
// opt.links("https://checkerframework.org/api/")
opt.isLinkSource = true
opt.bottom(File("$rootDir/javadocfooter.html").readText())
opt.isUse = true
opt.encoding("UTF-8")
opt.keyWords()
opt.addStringOption("-since", isRelease)
opt.noTimestamp()
}
}

View File

@ -24,9 +24,11 @@ import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Singleton;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
import com.plotsquared.bukkit.inject.BackupModule;
import com.plotsquared.bukkit.inject.BukkitModule;
import com.plotsquared.bukkit.inject.CloudModule;
import com.plotsquared.bukkit.inject.PermissionModule;
import com.plotsquared.bukkit.inject.WorldManagerModule;
import com.plotsquared.bukkit.listener.BlockEventListener;
@ -34,7 +36,6 @@ import com.plotsquared.bukkit.listener.BlockEventListener117;
import com.plotsquared.bukkit.listener.ChunkListener;
import com.plotsquared.bukkit.listener.EntityEventListener;
import com.plotsquared.bukkit.listener.EntitySpawnListener;
import com.plotsquared.bukkit.listener.HighFreqBlockEventListener;
import com.plotsquared.bukkit.listener.PaperListener;
import com.plotsquared.bukkit.listener.PlayerEventListener;
import com.plotsquared.bukkit.listener.PlayerEventListener1201;
@ -45,6 +46,7 @@ import com.plotsquared.bukkit.listener.SpigotListener;
import com.plotsquared.bukkit.listener.WorldEvents;
import com.plotsquared.bukkit.placeholder.PAPIPlaceholders;
import com.plotsquared.bukkit.placeholder.PlaceholderFormatter;
import com.plotsquared.bukkit.player.BukkitPlayer;
import com.plotsquared.bukkit.player.BukkitPlayerManager;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.bukkit.util.BukkitWorld;
@ -63,6 +65,7 @@ import com.plotsquared.bukkit.uuid.SquirrelIdUUIDService;
import com.plotsquared.core.PlotPlatform;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.backup.BackupManager;
import com.plotsquared.core.commands.PlotSquaredCommandManager;
import com.plotsquared.core.components.ComponentPresetManager;
import com.plotsquared.core.configuration.ConfigurationNode;
import com.plotsquared.core.configuration.ConfigurationSection;
@ -82,6 +85,7 @@ import com.plotsquared.core.inject.annotations.DefaultGenerator;
import com.plotsquared.core.inject.annotations.ImpromptuPipeline;
import com.plotsquared.core.inject.annotations.WorldConfig;
import com.plotsquared.core.inject.annotations.WorldFile;
import com.plotsquared.core.inject.modules.CommandModule;
import com.plotsquared.core.inject.modules.PlotSquaredModule;
import com.plotsquared.core.listener.PlotListener;
import com.plotsquared.core.listener.WESubscriber;
@ -292,6 +296,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
new PermissionModule(),
new WorldManagerModule(),
new PlotSquaredModule(),
new CommandModule(),
new CloudModule(this),
new BukkitModule(this),
new BackupModule()
);
@ -363,9 +369,6 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
getServer().getPluginManager().registerEvents(injector().getInstance(PlayerEventListener1201.class), this);
}
getServer().getPluginManager().registerEvents(injector().getInstance(BlockEventListener.class), this);
if (Settings.HIGH_FREQUENCY_LISTENER) {
getServer().getPluginManager().registerEvents(injector().getInstance(HighFreqBlockEventListener.class), this);
}
if (serverVersion()[1] >= 17) {
getServer().getPluginManager().registerEvents(injector().getInstance(BlockEventListener117.class), this);
}
@ -390,6 +393,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
// Commands
if (Settings.Enabled_Components.COMMANDS) {
this.registerCommands();
// Register the commands.
this.injector().getInstance(PlotSquaredCommandManager.class).registerDefaultCommands();
}
// Permissions
@ -781,31 +786,22 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
Iterator<Entity> iterator = entities.iterator();
while (iterator.hasNext()) {
Entity entity = iterator.next();
//noinspection ConstantValue - getEntitySpawnReason annotated as NotNull, but is not NotNull. lol.
if (PaperLib.isPaper() && entity.getEntitySpawnReason() != null && "CUSTOM".equals(entity.getEntitySpawnReason().name())) {
continue;
}
// Fallback for Spigot not having Entity#getEntitySpawnReason
if (entity.getMetadata("ps_custom_spawned").stream().anyMatch(MetadataValue::asBoolean)) {
continue;
}
// TODO: use (type) pattern matching when targeting java 21
switch (entity.getType().toString()) {
case "EGG":
case "FISHING_HOOK", "FISHING_BOBBER":
case "ENDER_SIGNAL", "EYE_OF_ENDER":
case "FISHING_HOOK":
case "ENDER_SIGNAL":
case "AREA_EFFECT_CLOUD":
case "EXPERIENCE_ORB":
case "LEASH_HITCH", "LEASH_KNOT":
case "FIREWORK", "FIREWORK_ROCKET":
case "LIGHTNING", "LIGHTNING_BOLT":
case "LEASH_HITCH":
case "FIREWORK":
case "LIGHTNING":
case "WITHER_SKULL":
case "UNKNOWN":
case "PLAYER":
// non moving / unmovable
continue;
case "THROWN_EXP_BOTTLE", "EXPERIENCE_BOTTLE":
case "SPLASH_POTION", "POTION":
case "THROWN_EXP_BOTTLE":
case "SPLASH_POTION":
case "SNOWBALL":
case "SHULKER_BULLET":
case "SPECTRAL_ARROW":
@ -823,25 +819,14 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
// Temporarily classify as vehicle
case "MINECART":
case "MINECART_CHEST":
case "CHEST_MINECART":
case "MINECART_COMMAND":
case "COMMAND_BLOCK_MINECART":
case "MINECART_FURNACE":
case "FURNACE_MINECART":
case "MINECART_HOPPER":
case "HOPPER_MINECART":
case "MINECART_MOB_SPAWNER":
case "SPAWNER_MINECART":
case "ENDER_CRYSTAL":
case "MINECART_TNT":
case "TNT_MINECART":
case "CHEST_BOAT":
case "BOAT":
case "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT",
"OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT":
case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT",
"JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT",
"SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT":
if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) {
com.plotsquared.core.location.Location location = BukkitUtil.adapt(entity.getLocation());
Plot plot = location.getPlot();
@ -870,14 +855,14 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
case "SMALL_FIREBALL":
case "FIREBALL":
case "DRAGON_FIREBALL":
case "DROPPED_ITEM", "ITEM":
case "DROPPED_ITEM":
if (Settings.Enabled_Components.KILL_ROAD_ITEMS
&& plotArea.getOwnedPlotAbs(BukkitUtil.adapt(entity.getLocation())) == null) {
this.removeRoadEntity(entity, iterator);
}
// dropped item
continue;
case "PRIMED_TNT", "TNT":
case "PRIMED_TNT":
case "FALLING_BLOCK":
// managed elsewhere
continue;
@ -889,7 +874,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
if (livingEntity.isLeashed() && !Settings.Enabled_Components.KILL_OWNED_ROAD_MOBS) {
continue;
}
if (entity.hasMetadata("keep")) {
List<MetadataValue> keep = entity.getMetadata("keep");
if (!keep.isEmpty()) {
continue;
}
@ -955,7 +941,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
case "HORSE":
case "IRON_GOLEM":
case "MAGMA_CUBE":
case "MUSHROOM_COW", "MOOSHROOM":
case "MUSHROOM_COW":
case "OCELOT":
case "PIG":
case "PIG_ZOMBIE":
@ -964,7 +950,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
case "SILVERFISH":
case "SKELETON":
case "SLIME":
case "SNOWMAN", "SNOW_GOLEM":
case "SNOWMAN":
case "SPIDER":
case "SQUID":
case "VILLAGER":
@ -1177,9 +1163,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
@Override
public @NonNull String serverNativePackage() {
final String name = Bukkit.getServer().getClass().getPackage().getName();
String ver = name.substring(name.lastIndexOf('.') + 1);
// org.bukkit.craftbukkit is no longer suffixed by a version
return ver.equals("craftbukkit") ? "" : ver;
return name.substring(name.lastIndexOf('.') + 1);
}
@Override
@ -1287,13 +1271,15 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
@Override
public @NonNull PlatformWorldManager<?> worldManager() {
return this.worldManager;
return injector().getInstance(Key.get(new TypeLiteral<PlatformWorldManager<World>>() {
}));
}
@Override
@NonNull
@SuppressWarnings("unchecked")
public PlayerManager<? extends PlotPlayer<Player>, ? extends Player> playerManager() {
return this.playerManager;
return (PlayerManager<BukkitPlayer, Player>) injector().getInstance(PlayerManager.class);
}
@Override

View File

@ -0,0 +1,50 @@
/*
* 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.commands;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.core.player.ConsolePlayer;
import com.plotsquared.core.player.PlotPlayer;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.SenderMapper;
/**
* Mapper between {@link CommandSender} and {@link PlotPlayer}.
*/
public final class BukkitSenderMapper implements SenderMapper<CommandSender, PlotPlayer<?>> {
@Override
public @NonNull PlotPlayer<?> map(final @NonNull CommandSender base) {
if (base instanceof Player player) {
return BukkitUtil.adapt(player);
}
return ConsolePlayer.getConsole();
}
@Override
public @NonNull CommandSender reverse(final @NonNull PlotPlayer<?> mapped) {
if (mapped instanceof ConsolePlayer) {
return Bukkit.getConsoleSender();
}
return (Player) mapped.getPlatformPlayer();
}
}

View File

@ -25,6 +25,7 @@ import org.bukkit.Art;
import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Rotation;
import org.bukkit.TreeSpecies;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.AbstractHorse;
@ -33,7 +34,6 @@ import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Breedable;
import org.bukkit.entity.ChestBoat;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Entity;
@ -44,6 +44,7 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Slime;
import org.bukkit.entity.Tameable;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.InventoryHolder;
@ -102,19 +103,11 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
this.noGravity = true;
}
switch (entity.getType().toString()) {
case "BOAT", "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT",
"OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT" -> {
case "BOAT" -> {
Boat boat = (Boat) entity;
this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType());
this.dataByte = getOrdinal(TreeSpecies.values(), boat.getWoodType());
return;
}
case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT",
"JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT",
"SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT" -> {
ChestBoat boat = (ChestBoat) entity;
this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType());
storeInventory(boat);
}
case "ARROW", "EGG", "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",
@ -124,7 +117,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
return;
}
// MISC //
case "DROPPED_ITEM", "ITEM" -> {
case "DROPPED_ITEM" -> {
Item item = (Item) entity;
this.stack = item.getItemStack();
return;
@ -154,14 +147,14 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
}
// END MISC //
// INVENTORY HOLDER //
case "MINECART_CHEST", "CHEST_MINECART", "MINECART_HOPPER", "HOPPER_MINECART" -> {
case "MINECART_CHEST", "MINECART_HOPPER" -> {
storeInventory((InventoryHolder) entity);
return;
}
// START LIVING ENTITY //
// START AGEABLE //
// START TAMEABLE //
case "CAMEL", "HORSE", "DONKEY", "LLAMA", "TRADER_LLAMA", "MULE", "SKELETON_HORSE", "ZOMBIE_HORSE" -> {
case "HORSE", "DONKEY", "LLAMA", "MULE", "SKELETON_HORSE" -> {
AbstractHorse horse = (AbstractHorse) entity;
this.horse = new HorseStats();
this.horse.jump = horse.getJumpStrength();
@ -179,13 +172,14 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
return;
}
// END INVENTORY HOLDER //
case "WOLF", "OCELOT", "CAT", "PARROT" -> {
case "WOLF", "OCELOT" -> {
storeTameable((Tameable) entity);
storeBreedable((Breedable) entity);
storeLiving((LivingEntity) entity);
return;
}
// END TAMEABLE //
//todo fix sheep
case "SHEEP" -> {
Sheep sheep = (Sheep) entity;
if (sheep.isSheared()) {
@ -193,7 +187,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
} else {
this.dataByte = (byte) 0;
}
this.dataByte2 = getOrdinal(DyeColor.values(), sheep.getColor());
this.dataByte2 = sheep.getColor().getDyeData();
storeBreedable(sheep);
storeLiving(sheep);
return;
@ -274,7 +268,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
}
case "SKELETON", "WITHER_SKELETON", "GUARDIAN", "ELDER_GUARDIAN", "GHAST", "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" -> {
"GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SHULKER", "SNOWMAN" -> {
storeLiving((LivingEntity) entity);
return;
}
@ -456,7 +450,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
}
Entity entity;
switch (this.getType().toString()) {
case "DROPPED_ITEM", "ITEM" -> {
case "DROPPED_ITEM" -> {
return world.dropItem(location, this.stack);
}
case "PLAYER", "LEASH_HITCH" -> {
@ -492,25 +486,15 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
entity.setGravity(false);
}
switch (entity.getType().toString()) {
case "BOAT", "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT",
"OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT" -> {
case "BOAT" -> {
Boat boat = (Boat) entity;
boat.setBoatType(Boat.Type.values()[dataByte]);
boat.setWoodType(TreeSpecies.values()[dataByte]);
return entity;
}
case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT",
"JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT",
"SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT" -> {
ChestBoat boat = (ChestBoat) entity;
boat.setBoatType(Boat.Type.values()[dataByte]);
restoreInventory(boat);
return entity;
}
// SLIME is not even stored
/* case "SLIME" -> {
case "SLIME" -> {
((Slime) entity).setSize(this.dataByte);
return entity;
} */
}
case "ARROW", "EGG", "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",
@ -534,14 +518,14 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
}
// END MISC //
// INVENTORY HOLDER //
case "MINECART_CHEST", "CHEST_MINECART", "MINECART_HOPPER", "HOPPER_MINECART" -> {
case "MINECART_CHEST", "MINECART_HOPPER" -> {
restoreInventory((InventoryHolder) entity);
return entity;
}
// START LIVING ENTITY //
// START AGEABLE //
// START TAMEABLE //
case "CAMEL", "HORSE", "DONKEY", "LLAMA", "TRADER_LLAMA", "MULE", "SKELETON_HORSE", "ZOMBIE_HORSE" -> {
case "HORSE", "LLAMA", "SKELETON_HORSE", "DONKEY", "MULE" -> {
AbstractHorse horse = (AbstractHorse) entity;
horse.setJumpStrength(this.horse.jump);
if (horse instanceof ChestedHorse) {
@ -558,7 +542,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
return entity;
}
// END INVENTORY HOLDER //
case "WOLF", "OCELOT", "CAT", "PARROT" -> {
case "WOLF", "OCELOT" -> {
restoreTameable((Tameable) entity);
restoreBreedable((Breedable) entity);
restoreLiving((LivingEntity) entity);
@ -571,7 +555,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
sheep.setSheared(true);
}
if (this.dataByte2 != 0) {
sheep.setColor(DyeColor.values()[this.dataByte2]);
sheep.setColor(DyeColor.getByDyeData(this.dataByte2));
}
restoreBreedable(sheep);
restoreLiving(sheep);

View File

@ -52,7 +52,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
@ -445,7 +445,7 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
private static final List<Biome> BIOMES;
static {
Set<Biome> disabledBiomes = new HashSet<>(List.of(Biome.CUSTOM));
Set<Biome> disabledBiomes = EnumSet.of(Biome.CUSTOM);
if (PlotSquared.platform().serverVersion()[1] <= 19) {
final Biome cherryGrove = Registry.BIOME.get(NamespacedKey.minecraft("cherry_grove"));
if (cherryGrove != null) {

View File

@ -0,0 +1,99 @@
/*
* 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.inject;
import com.google.inject.AbstractModule;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.bukkit.commands.BukkitSenderMapper;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.core.commands.CommandRequirement;
import com.plotsquared.core.commands.PlotSquaredCaptionProvider;
import com.plotsquared.core.commands.PlotSquaredRequirementFailureHandler;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.ConsolePlayer;
import com.plotsquared.core.player.PlotPlayer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.minecraft.extras.MinecraftExceptionHandler;
import org.incendo.cloud.paper.PaperCommandManager;
import org.incendo.cloud.processors.requirements.RequirementPostprocessor;
public class CloudModule extends AbstractModule {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + CloudModule.class.getSimpleName());
private static @NonNull CommandSender convert(final @NonNull PlotPlayer<?> player) {
if (player instanceof ConsolePlayer) {
return Bukkit.getConsoleSender();
}
return (Player) player.getPlatformPlayer();
}
private static @NonNull PlotPlayer<?> convert (final @NonNull CommandSender sender) {
if (sender instanceof Player player) {
return BukkitUtil.adapt(player);
}
return ConsolePlayer.getConsole();
}
private final BukkitPlatform bukkitPlatform;
public CloudModule(final @NonNull BukkitPlatform bukkitPlatform) {
this.bukkitPlatform = bukkitPlatform;
}
@Override
protected void configure() {
final PaperCommandManager<PlotPlayer<?>> commandManager = new PaperCommandManager<PlotPlayer<?>>(
this.bukkitPlatform,
ExecutionCoordinator.asyncCoordinator(),
new BukkitSenderMapper()
);
commandManager.captionRegistry().registerProvider(new PlotSquaredCaptionProvider());
if (commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
commandManager.registerBrigadier();
} else if (commandManager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
commandManager.registerAsynchronousCompletions();
}
final RequirementPostprocessor<PlotPlayer<?>, CommandRequirement> requirementPostprocessor =
RequirementPostprocessor.of(CommandRequirement.REQUIREMENTS_KEY, new PlotSquaredRequirementFailureHandler());
commandManager.registerCommandPostProcessor(requirementPostprocessor);
// TODO(City): Override parsing errors using MM parsing.
MinecraftExceptionHandler.<PlotPlayer<?>>create(PlotPlayer::getAudience)
.defaultHandlers()
.decorator((ctx, component) -> TranslatableCaption.of("core.prefix").
toComponent(ctx.context().sender())
.append(component))
.registerTo(commandManager);
bind(Key.get(new TypeLiteral<CommandManager<PlotPlayer<?>>>() {})).toInstance(commandManager);
}
}

View File

@ -24,6 +24,7 @@ import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.database.DBFunc;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
@ -47,6 +48,7 @@ import com.plotsquared.core.plot.flag.implementations.LeafDecayFlag;
import com.plotsquared.core.plot.flag.implementations.LiquidFlowFlag;
import com.plotsquared.core.plot.flag.implementations.MycelGrowFlag;
import com.plotsquared.core.plot.flag.implementations.PlaceFlag;
import com.plotsquared.core.plot.flag.implementations.RedstoneFlag;
import com.plotsquared.core.plot.flag.implementations.SnowFormFlag;
import com.plotsquared.core.plot.flag.implementations.SnowMeltFlag;
import com.plotsquared.core.plot.flag.implementations.SoilDryFlag;
@ -60,6 +62,7 @@ import com.plotsquared.core.util.task.TaskTime;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.block.BlockType;
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.bukkit.Bukkit;
@ -89,9 +92,11 @@ import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockGrowEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockMultiPlaceEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.CauldronLevelChangeEvent;
import org.bukkit.event.block.EntityBlockFormEvent;
@ -106,6 +111,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.bukkit.Tag.CORALS;
import static org.bukkit.Tag.CORAL_BLOCKS;
@ -113,6 +122,20 @@ import static org.bukkit.Tag.WALL_CORALS;
@SuppressWarnings("unused")
public class BlockEventListener implements Listener {
private static final Set<Material> PISTONS = Set.of(
Material.PISTON,
Material.STICKY_PISTON
);
private static final Set<Material> PHYSICS_BLOCKS = Set.of(
Material.TURTLE_EGG,
Material.TURTLE_SPAWN_EGG
);
private static final Set<Material> SNOW = Stream.of(Material.values()) // needed as Tag.SNOW isn't present in 1.16.5
.filter(material -> material.name().contains("SNOW"))
.filter(Material::isBlock)
.collect(Collectors.toUnmodifiableSet());
private final PlotAreaManager plotAreaManager;
private final WorldEdit worldEdit;
@ -141,6 +164,114 @@ public class BlockEventListener implements Listener {
}, TaskTime.ticks(3L));
}
@EventHandler
public void onRedstoneEvent(BlockRedstoneEvent event) {
Block block = event.getBlock();
Location location = BukkitUtil.adapt(block.getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = location.getOwnedPlot();
if (plot == null) {
if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, RedstoneFlag.class, false)) {
event.setNewCurrent(0);
}
return;
}
if (!plot.getFlag(RedstoneFlag.class)) {
event.setNewCurrent(0);
plot.debug("Redstone event was cancelled because redstone = false");
return;
}
if (Settings.Redstone.DISABLE_OFFLINE) {
boolean disable = false;
if (!DBFunc.SERVER.equals(plot.getOwner())) {
if (plot.isMerged()) {
disable = true;
for (UUID owner : plot.getOwners()) {
if (PlotSquared.platform().playerManager().getPlayerIfExists(owner) != null) {
disable = false;
break;
}
}
} else {
disable = PlotSquared.platform().playerManager().getPlayerIfExists(plot.getOwnerAbs()) == null;
}
}
if (disable) {
for (UUID trusted : plot.getTrusted()) {
if (PlotSquared.platform().playerManager().getPlayerIfExists(trusted) != null) {
disable = false;
break;
}
}
if (disable) {
event.setNewCurrent(0);
plot.debug("Redstone event was cancelled because no trusted player was in the plot");
return;
}
}
}
if (Settings.Redstone.DISABLE_UNOCCUPIED) {
for (final PlotPlayer<?> player : PlotSquared.platform().playerManager().getPlayers()) {
if (plot.equals(player.getCurrentPlot())) {
return;
}
}
event.setNewCurrent(0);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPhysicsEvent(BlockPhysicsEvent event) {
Block block = event.getBlock();
Location location = BukkitUtil.adapt(block.getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = area.getOwnedPlotAbs(location);
if (plot == null) {
return;
}
if (event.getChangedType().hasGravity() && plot.getFlag(DisablePhysicsFlag.class)) {
event.setCancelled(true);
sendBlockChange(event.getBlock().getLocation(), event.getBlock().getBlockData());
plot.debug("Prevented block physics and resent block change because disable-physics = true");
return;
}
if (event.getChangedType() == Material.COMPARATOR) {
if (!plot.getFlag(RedstoneFlag.class)) {
event.setCancelled(true);
plot.debug("Prevented comparator update because redstone = false");
}
return;
}
if (PHYSICS_BLOCKS.contains(event.getChangedType())) {
if (plot.getFlag(DisablePhysicsFlag.class)) {
event.setCancelled(true);
plot.debug("Prevented block physics because disable-physics = true");
}
return;
}
if (Settings.Redstone.DETECT_INVALID_EDGE_PISTONS) {
if (PISTONS.contains(block.getType())) {
org.bukkit.block.data.Directional piston = (org.bukkit.block.data.Directional) block.getBlockData();
final BlockFace facing = piston.getFacing();
location = location.add(facing.getModX(), facing.getModY(), facing.getModZ());
Plot newPlot = area.getOwnedPlotAbs(location);
if (plot.equals(newPlot)) {
return;
}
if (!plot.isMerged() || !plot.getConnectedPlots().contains(newPlot)) {
event.setCancelled(true);
plot.debug("Prevented piston update because of invalid edge piston detection");
}
}
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void blockCreate(BlockPlaceEvent event) {
Location location = BukkitUtil.adapt(event.getBlock().getLocation());
@ -154,6 +285,13 @@ public class BlockEventListener implements Listener {
if (plot != null) {
if (area.notifyIfOutsideBuildArea(pp, location.getY())) {
event.setCancelled(true);
pp.sendMessage(
TranslatableCaption.of("height.height_limit"),
TagResolver.builder()
.tag("minheight", Tag.inserting(Component.text(area.getMinBuildHeight())))
.tag("maxheight", Tag.inserting(Component.text(area.getMaxBuildHeight())))
.build()
);
return;
}
if (!plot.hasOwner()) {
@ -245,6 +383,13 @@ public class BlockEventListener implements Listener {
}
} else if (area.notifyIfOutsideBuildArea(plotPlayer, location.getY())) {
event.setCancelled(true);
plotPlayer.sendMessage(
TranslatableCaption.of("height.height_limit"),
TagResolver.builder()
.tag("minheight", Tag.inserting(Component.text(area.getMinBuildHeight())))
.tag("maxheight", Tag.inserting(Component.text(area.getMaxBuildHeight())))
.build()
);
return;
}
if (!plot.hasOwner()) {
@ -525,11 +670,7 @@ public class BlockEventListener implements Listener {
BlockBreakEvent call = new BlockBreakEvent(block, player);
Bukkit.getServer().getPluginManager().callEvent(call);
if (!call.isCancelled()) {
if (Settings.Flags.INSTABREAK_CONSIDER_TOOL) {
block.breakNaturally(event.getItemInHand());
} else {
block.breakNaturally();
}
event.getBlock().breakNaturally();
}
}
// == rather than <= as we only care about the "ground level" not being destroyed
@ -1200,9 +1341,18 @@ public class BlockEventListener implements Listener {
if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) {
continue;
}
if (area.notifyIfOutsideBuildArea(pp, currentLocation.getY())) {
event.setCancelled(true);
break;
if (currentLocation.getY() >= area.getMaxBuildHeight() || currentLocation.getY() < area.getMinBuildHeight()) {
pp.sendMessage(
TranslatableCaption.of("height.height_limit"),
TagResolver.builder()
.tag("minheight", Tag.inserting(Component.text(area.getMinBuildHeight())))
.tag("maxheight", Tag.inserting(Component.text(area.getMaxBuildHeight())))
.build()
);
if (area.notifyIfOutsideBuildArea(pp, currentLocation.getY())) {
event.setCancelled(true);
break;
}
}
}

View File

@ -134,7 +134,7 @@ public class BlockEventListener117 implements Listener {
public void onBlockFertilize(BlockFertilizeEvent event) {
Block block = event.getBlock();
List<org.bukkit.block.BlockState> blocks = event.getBlocks();
Location location = BukkitUtil.adapt(block.getLocation());
Location location = BukkitUtil.adapt(blocks.get(0).getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {

View File

@ -19,7 +19,6 @@
package com.plotsquared.bukkit.listener;
import com.google.inject.Inject;
import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.bukkit.player.BukkitPlayer;
import com.plotsquared.bukkit.util.BukkitEntityUtil;
import com.plotsquared.bukkit.util.BukkitUtil;
@ -37,14 +36,11 @@ import com.plotsquared.core.plot.flag.implementations.EntityChangeBlockFlag;
import com.plotsquared.core.plot.flag.implementations.ExplosionFlag;
import com.plotsquared.core.plot.flag.implementations.InvincibleFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectileChangeBlockFlag;
import com.plotsquared.core.plot.flag.implementations.WeavingDeathPlace;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.PlotFlagUtil;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.util.Enums;
import com.sk89q.worldedit.world.block.BlockType;
import io.papermc.lib.PaperLib;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
@ -58,8 +54,6 @@ import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -80,54 +74,56 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@SuppressWarnings("unused")
public class EntityEventListener implements Listener {
private static final Particle EXPLOSION_HUGE = Objects.requireNonNull(Enums.findByValue(
Particle.class,
"EXPLOSION_EMITTER",
"EXPLOSION_HUGE"
));
private final BukkitPlatform platform;
private final PlotAreaManager plotAreaManager;
private final EventDispatcher eventDispatcher;
private float lastRadius;
@Inject
public EntityEventListener(
final @NonNull BukkitPlatform platform,
final @NonNull PlotAreaManager plotAreaManager,
final @NonNull EventDispatcher eventDispatcher
) {
this.platform = platform;
this.plotAreaManager = plotAreaManager;
this.eventDispatcher = eventDispatcher;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onEntityCombustByEntity(EntityCombustByEntityEvent event) {
onEntityDamageByEntityCommon(event.getCombuster(), event.getEntity(), EntityDamageEvent.DamageCause.FIRE_TICK, event);
EntityDamageByEntityEvent eventChange =
new EntityDamageByEntityEvent(
event.getCombuster(),
event.getEntity(),
EntityDamageEvent.DamageCause.FIRE_TICK,
event.getDuration()
);
onEntityDamageByEntityEvent(eventChange);
if (eventChange.isCancelled()) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) {
onEntityDamageByEntityCommon(event.getDamager(), event.getEntity(), event.getCause(), event);
}
private void onEntityDamageByEntityCommon(
final Entity damager,
final Entity victim,
final EntityDamageEvent.DamageCause cause,
final Cancellable event
) {
Entity damager = event.getDamager();
Location location = BukkitUtil.adapt(damager.getLocation());
if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) {
return;
}
if (!BukkitEntityUtil.entityDamage(damager, victim, cause)) {
Entity victim = event.getEntity();
/*
if (victim.getType().equals(EntityType.ITEM_FRAME)) {
Plot plot = BukkitUtil.getLocation(victim).getPlot();
if (plot != null && !plot.isAdded(damager.getUniqueId())) {
event.setCancelled(true);
return;
}
}
*/
if (!BukkitEntityUtil.entityDamage(damager, victim, event.getCause())) {
if (event.isCancelled()) {
if (victim instanceof Ageable ageable) {
if (ageable.getAge() == -24000) {
@ -161,31 +157,20 @@ public class EntityEventListener implements Listener {
}
}
case "REINFORCEMENTS", "NATURAL", "MOUNT", "PATROL", "RAID", "SHEARED", "SILVERFISH_BLOCK", "ENDER_PEARL",
"TRAP", "VILLAGE_DEFENSE", "VILLAGE_INVASION", "BEEHIVE", "CHUNK_GEN", "NETHER_PORTAL",
"FROZEN", "SPELL", "DEFAULT" -> {
"TRAP", "VILLAGE_DEFENSE", "VILLAGE_INVASION", "BEEHIVE", "CHUNK_GEN", "NETHER_PORTAL",
"DUPLICATION", "FROZEN", "SPELL", "DEFAULT" -> {
if (!area.isMobSpawning()) {
event.setCancelled(true);
return;
}
}
case "BREEDING", "DUPLICATION" -> {
case "BREEDING" -> {
if (!area.isSpawnBreeding()) {
event.setCancelled(true);
return;
}
}
case "CUSTOM" -> {
if (!area.isSpawnCustom()) {
event.setCancelled(true);
return;
}
// No need to clutter metadata if running paper
if (!PaperLib.isPaper()) {
entity.setMetadata("ps_custom_spawned", new FixedMetadataValue(this.platform, true));
}
return; // Don't cancel if mob spawning is disabled
}
case "BUILD_IRONGOLEM", "BUILD_SNOWMAN", "BUILD_WITHER" -> {
case "BUILD_IRONGOLEM", "BUILD_SNOWMAN", "BUILD_WITHER", "CUSTOM" -> {
if (!area.isSpawnCustom()) {
event.setCancelled(true);
return;
@ -253,29 +238,6 @@ public class EntityEventListener implements Listener {
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onWeavingEffect(EntityChangeBlockEvent event) {
if (event.getTo() != Material.COBWEB) {
return;
}
Location location = BukkitUtil.adapt(event.getBlock().getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = location.getOwnedPlot();
if (plot == null) {
if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, WeavingDeathPlace.class, false)) {
event.setCancelled(true);
}
return;
}
if (!plot.getFlag(WeavingDeathPlace.class)) {
plot.debug(event.getTo() + " could not spawn because weaving-death-place = false");
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onDamage(EntityDamageEvent event) {
if (event.getEntityType() != EntityType.PLAYER) {
@ -323,7 +285,7 @@ public class EntityEventListener implements Listener {
if (this.lastRadius != 0) {
List<Entity> nearby = event.getEntity().getNearbyEntities(this.lastRadius, this.lastRadius, this.lastRadius);
for (Entity near : nearby) {
if (near instanceof TNTPrimed || near instanceof ExplosiveMinecart) {
if (near instanceof TNTPrimed || near.getType().equals(EntityType.MINECART_TNT)) {
if (!near.hasMetadata("plot")) {
near.setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), plot));
}
@ -347,7 +309,7 @@ public class EntityEventListener implements Listener {
event.setCancelled(true);
//Spawn Explosion Particles when enabled in settings
if (Settings.General.ALWAYS_SHOW_EXPLOSIONS) {
event.getLocation().getWorld().spawnParticle(EXPLOSION_HUGE, event.getLocation(), 0);
event.getLocation().getWorld().spawnParticle(Particle.EXPLOSION_HUGE, event.getLocation(), 0);
}
}
@ -434,13 +396,7 @@ public class EntityEventListener implements Listener {
}
Plot plot = area.getOwnedPlot(location);
if (plot == null) {
if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, EntityChangeBlockFlag.class, false)) {
event.setCancelled(true);
}
return;
}
if (!plot.getFlag(EntityChangeBlockFlag.class)) {
if (plot != null && !plot.getFlag(EntityChangeBlockFlag.class)) {
plot.debug(e.getType() + " could not change block because entity-change-block = false");
event.setCancelled(true);
}

View File

@ -31,10 +31,8 @@ import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Item;
import org.bukkit.entity.Vehicle;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -122,19 +120,13 @@ public class EntitySpawnListener implements Listener {
Entity entity = event.getEntity();
Location location = BukkitUtil.adapt(entity.getLocation());
PlotArea area = location.getPlotArea();
if (!location.isPlotArea() || area == null) {
if (!location.isPlotArea()) {
return;
}
if (PaperLib.isPaper()) {
//noinspection ConstantValue - getEntitySpawnReason annotated as NotNull, but is not NotNull. lol.
if (area.isSpawnCustom() && entity.getEntitySpawnReason() != null && "CUSTOM".equals(entity.getEntitySpawnReason().name())) {
return;
}
}
Plot plot = location.getOwnedPlotAbs();
EntityType type = entity.getType();
if (plot == null) {
if (entity instanceof Item) {
if (type == EntityType.DROPPED_ITEM) {
if (Settings.Enabled_Components.KILL_ROAD_ITEMS) {
event.setCancelled(true);
}
@ -156,7 +148,7 @@ public class EntitySpawnListener implements Listener {
if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) {
event.setCancelled(true);
}
if (entity instanceof EnderCrystal || type == EntityType.ARMOR_STAND) {
if (type == EntityType.ENDER_CRYSTAL) {
if (BukkitEntityUtil.checkEntity(entity, plot)) {
event.setCancelled(true);
}

View File

@ -1,201 +0,0 @@
/*
* 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.listener;
import com.google.inject.Inject;
import com.plotsquared.bukkit.player.BukkitPlayer;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.database.DBFunc;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.flag.implementations.DisablePhysicsFlag;
import com.plotsquared.core.plot.flag.implementations.RedstoneFlag;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.PlotFlagUtil;
import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.util.task.TaskTime;
import com.sk89q.worldedit.WorldEdit;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Set;
import java.util.UUID;
@SuppressWarnings("unused")
public class HighFreqBlockEventListener implements Listener {
private static final Set<Material> PISTONS = Set.of(
Material.PISTON,
Material.STICKY_PISTON
);
private static final Set<Material> PHYSICS_BLOCKS = Set.of(
Material.TURTLE_EGG,
Material.TURTLE_SPAWN_EGG
);
private final PlotAreaManager plotAreaManager;
private final WorldEdit worldEdit;
@Inject
public HighFreqBlockEventListener(final @NonNull PlotAreaManager plotAreaManager, final @NonNull WorldEdit worldEdit) {
this.plotAreaManager = plotAreaManager;
this.worldEdit = worldEdit;
}
public static void sendBlockChange(final org.bukkit.Location bloc, final BlockData data) {
TaskManager.runTaskLater(() -> {
String world = bloc.getWorld().getName();
int x = bloc.getBlockX();
int z = bloc.getBlockZ();
int distance = Bukkit.getViewDistance() * 16;
for (final PlotPlayer<?> player : PlotSquared.platform().playerManager().getPlayers()) {
Location location = player.getLocation();
if (location.getWorldName().equals(world)) {
if (16 * Math.abs(location.getX() - x) / 16 > distance || 16 * Math.abs(location.getZ() - z) / 16 > distance) {
continue;
}
((BukkitPlayer) player).player.sendBlockChange(bloc, data);
}
}
}, TaskTime.ticks(3L));
}
@EventHandler
public void onRedstoneEvent(BlockRedstoneEvent event) {
Block block = event.getBlock();
Location location = BukkitUtil.adapt(block.getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = location.getOwnedPlot();
if (plot == null) {
if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, RedstoneFlag.class, false)) {
event.setNewCurrent(0);
}
return;
}
if (!plot.getFlag(RedstoneFlag.class)) {
event.setNewCurrent(0);
plot.debug("Redstone event was cancelled because redstone = false");
return;
}
if (Settings.Redstone.DISABLE_OFFLINE) {
boolean disable = false;
if (!DBFunc.SERVER.equals(plot.getOwner())) {
if (plot.isMerged()) {
disable = true;
for (UUID owner : plot.getOwners()) {
if (PlotSquared.platform().playerManager().getPlayerIfExists(owner) != null) {
disable = false;
break;
}
}
} else {
disable = PlotSquared.platform().playerManager().getPlayerIfExists(plot.getOwnerAbs()) == null;
}
}
if (disable) {
for (UUID trusted : plot.getTrusted()) {
if (PlotSquared.platform().playerManager().getPlayerIfExists(trusted) != null) {
disable = false;
break;
}
}
if (disable) {
event.setNewCurrent(0);
plot.debug("Redstone event was cancelled because no trusted player was in the plot");
return;
}
}
}
if (Settings.Redstone.DISABLE_UNOCCUPIED) {
for (final PlotPlayer<?> player : PlotSquared.platform().playerManager().getPlayers()) {
if (plot.equals(player.getCurrentPlot())) {
return;
}
}
event.setNewCurrent(0);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPhysicsEvent(BlockPhysicsEvent event) {
Block block = event.getBlock();
Location location = BukkitUtil.adapt(block.getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = area.getOwnedPlotAbs(location);
if (plot == null) {
return;
}
if (event.getChangedType().hasGravity() && plot.getFlag(DisablePhysicsFlag.class)) {
event.setCancelled(true);
sendBlockChange(event.getBlock().getLocation(), event.getBlock().getBlockData());
plot.debug("Prevented block physics and resent block change because disable-physics = true");
return;
}
if (event.getChangedType() == Material.COMPARATOR) {
if (!plot.getFlag(RedstoneFlag.class)) {
event.setCancelled(true);
plot.debug("Prevented comparator update because redstone = false");
}
return;
}
if (PHYSICS_BLOCKS.contains(event.getChangedType())) {
if (plot.getFlag(DisablePhysicsFlag.class)) {
event.setCancelled(true);
plot.debug("Prevented block physics because disable-physics = true");
}
return;
}
if (Settings.Redstone.DETECT_INVALID_EDGE_PISTONS) {
if (PISTONS.contains(block.getType())) {
org.bukkit.block.data.Directional piston = (org.bukkit.block.data.Directional) block.getBlockData();
final BlockFace facing = piston.getFacing();
location = location.add(facing.getModX(), facing.getModY(), facing.getModZ());
Plot newPlot = area.getOwnedPlotAbs(location);
if (plot.equals(newPlot)) {
return;
}
if (!plot.isMerged() || !plot.getConnectedPlots().contains(newPlot)) {
event.setCancelled(true);
plot.debug("Prevented piston update because of invalid edge piston detection");
}
}
}
}
}

View File

@ -19,7 +19,6 @@
package com.plotsquared.bukkit.listener;
import com.destroystokyo.paper.event.block.BeaconEffectEvent;
import com.destroystokyo.paper.event.block.BlockDestroyEvent;
import com.destroystokyo.paper.event.entity.EntityPathfindEvent;
import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent;
import com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent;
@ -41,18 +40,14 @@ import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.flag.FlagContainer;
import com.plotsquared.core.plot.flag.implementations.BeaconEffectsFlag;
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
import com.plotsquared.core.plot.flag.implementations.FishingFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag;
import com.plotsquared.core.plot.flag.implementations.TileDropFlag;
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 net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Chunk;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.TileState;
import org.bukkit.entity.Entity;
@ -60,7 +55,6 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Slime;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -81,9 +75,6 @@ import java.util.regex.Pattern;
@SuppressWarnings("unused")
public class PaperListener implements Listener {
private static final NamespacedKey ITEM = NamespacedKey.minecraft("item");
private static final NamespacedKey FISHING_BOBBER = NamespacedKey.minecraft("fishing_bobber");
private final PlotAreaManager plotAreaManager;
private Chunk lastChunk;
@ -92,56 +83,13 @@ public class PaperListener implements Listener {
this.plotAreaManager = plotAreaManager;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onBlockDestroy(final BlockDestroyEvent event) {
Location location = BukkitUtil.adapt(event.getBlock().getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = area.getPlot(location);
if (plot != null) {
event.setWillDrop(plot.getFlag(TileDropFlag.class));
}
}
@EventHandler
public void onEntityPathfind(EntityPathfindEvent event) {
if (!Settings.Paper_Components.ENTITY_PATHING) {
return;
}
handleEntityMovement(event, event.getEntity().getLocation(), event.getLoc());
}
@EventHandler
public void onEntityPathfind(SlimePathfindEvent event) {
if (!Settings.Paper_Components.ENTITY_PATHING) {
return;
}
Slime slime = event.getEntity();
Block b = slime.getTargetBlockExact(4);
if (b == null) {
return;
}
handleEntityMovement(event, event.getEntity().getLocation(), b.getLocation());
}
@EventHandler
public void onEntityMove(EntityMoveEvent event) {
if (!Settings.Paper_Components.ENTITY_MOVEMENT) {
return;
}
if (!event.hasExplicitlyChangedBlock()) {
return;
}
handleEntityMovement(event, event.getFrom(), event.getTo());
}
private static void handleEntityMovement(Cancellable event, org.bukkit.Location from, org.bukkit.Location target) {
Location toLoc = BukkitUtil.adapt(target);
Location fromLoc = BukkitUtil.adapt(from);
Location toLoc = BukkitUtil.adapt(event.getLoc());
Location fromLoc = BukkitUtil.adapt(event.getEntity().getLocation());
PlotArea tarea = toLoc.getPlotArea();
if (tarea == null) {
return;
@ -160,10 +108,52 @@ public class PaperListener implements Listener {
event.setCancelled(true);
return;
}
if (tplot == null || tplot.getId().equals(fplot.getId())) {
if (tplot == null || tplot.getId().hashCode() == fplot.getId().hashCode()) {
return;
}
if (fplot.isMerged() && fplot.getConnectedPlots().contains(tplot)) {
if (fplot.isMerged() && fplot.getConnectedPlots().contains(fplot)) {
return;
}
event.setCancelled(true);
}
@EventHandler
public void onEntityPathfind(SlimePathfindEvent event) {
if (!Settings.Paper_Components.ENTITY_PATHING) {
return;
}
Slime slime = event.getEntity();
Block b = slime.getTargetBlockExact(4);
if (b == null) {
return;
}
Location toLoc = BukkitUtil.adapt(b.getLocation());
Location fromLoc = BukkitUtil.adapt(event.getEntity().getLocation());
PlotArea tarea = toLoc.getPlotArea();
if (tarea == null) {
return;
}
PlotArea farea = fromLoc.getPlotArea();
if (farea == null) {
return;
}
if (tarea != farea) {
event.setCancelled(true);
return;
}
Plot tplot = toLoc.getPlot();
Plot fplot = fromLoc.getPlot();
if (tplot == null ^ fplot == null) {
event.setCancelled(true);
return;
}
if (tplot == null || tplot.getId().hashCode() == fplot.getId().hashCode()) {
return;
}
if (fplot.isMerged() && fplot.getConnectedPlots().contains(fplot)) {
return;
}
event.setCancelled(true);
@ -232,7 +222,7 @@ public class PaperListener implements Listener {
if (plot == null) {
EntityType type = event.getType();
// PreCreatureSpawnEvent **should** not be called for DROPPED_ITEM, just for the sake of consistency
if (type.getKey().equals(ITEM)) {
if (type == EntityType.DROPPED_ITEM) {
if (Settings.Enabled_Components.KILL_ROAD_ITEMS) {
event.setCancelled(true);
}
@ -358,11 +348,6 @@ public class PaperListener implements Listener {
event.setCancelled(true);
}
} else if (!plot.isAdded(pp.getUUID())) {
if (entity.getType().getKey().equals(FISHING_BOBBER)) {
if (plot.getFlag(FishingFlag.class)) {
return;
}
}
if (!plot.getFlag(ProjectilesFlag.class)) {
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
pp.sendMessage(

View File

@ -54,7 +54,6 @@ import com.plotsquared.core.plot.flag.implementations.EditSignFlag;
import com.plotsquared.core.plot.flag.implementations.HangingBreakFlag;
import com.plotsquared.core.plot.flag.implementations.HangingPlaceFlag;
import com.plotsquared.core.plot.flag.implementations.HostileInteractFlag;
import com.plotsquared.core.plot.flag.implementations.InteractionInteractFlag;
import com.plotsquared.core.plot.flag.implementations.ItemDropFlag;
import com.plotsquared.core.plot.flag.implementations.KeepInventoryFlag;
import com.plotsquared.core.plot.flag.implementations.LecternReadBookFlag;
@ -62,7 +61,6 @@ import com.plotsquared.core.plot.flag.implementations.MiscInteractFlag;
import com.plotsquared.core.plot.flag.implementations.PlayerInteractFlag;
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.VehicleBreakFlag;
import com.plotsquared.core.plot.flag.implementations.VehicleUseFlag;
@ -109,7 +107,6 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.entity.EntityPlaceEvent;
import org.bukkit.event.entity.EntityPotionEffectEvent;
@ -202,76 +199,11 @@ public class PlayerEventListener implements Listener {
"GLOW_INK_SAC"
));
int[] version = PlotSquared.platform().serverVersion();
if (version[1] >= 20) {
if (version[1] >= 20 && version[2] >= 1) {
mutableDyes.add("HONEYCOMB");
}
DYES = Set.copyOf(mutableDyes);
}
private static final Set<String> INTERACTABLE_MATERIALS;
static {
// @formatter:off
// "temporary" fix for https://hub.spigotmc.org/jira/browse/SPIGOT-7813
// can (and should) be removed when 1.21 support is dropped
// List of all interactable 1.21 materials
INTERACTABLE_MATERIALS = Material.CHEST.isInteractable() ? null : Set.of(
"REDSTONE_ORE", "DEEPSLATE_REDSTONE_ORE", "CHISELED_BOOKSHELF", "DECORATED_POT", "CHEST", "CRAFTING_TABLE",
"FURNACE", "JUKEBOX", "OAK_FENCE", "SPRUCE_FENCE", "BIRCH_FENCE", "JUNGLE_FENCE", "ACACIA_FENCE", "CHERRY_FENCE",
"DARK_OAK_FENCE", "MANGROVE_FENCE", "BAMBOO_FENCE", "CRIMSON_FENCE", "WARPED_FENCE", "PUMPKIN",
"NETHER_BRICK_FENCE", "ENCHANTING_TABLE", "DRAGON_EGG", "ENDER_CHEST", "COMMAND_BLOCK", "BEACON", "ANVIL",
"CHIPPED_ANVIL", "DAMAGED_ANVIL", "LIGHT", "REPEATING_COMMAND_BLOCK", "CHAIN_COMMAND_BLOCK", "SHULKER_BOX",
"WHITE_SHULKER_BOX", "ORANGE_SHULKER_BOX", "MAGENTA_SHULKER_BOX", "LIGHT_BLUE_SHULKER_BOX", "YELLOW_SHULKER_BOX",
"LIME_SHULKER_BOX", "PINK_SHULKER_BOX", "GRAY_SHULKER_BOX", "LIGHT_GRAY_SHULKER_BOX", "CYAN_SHULKER_BOX",
"PURPLE_SHULKER_BOX", "BLUE_SHULKER_BOX", "BROWN_SHULKER_BOX", "GREEN_SHULKER_BOX", "RED_SHULKER_BOX",
"BLACK_SHULKER_BOX", "REPEATER", "COMPARATOR", "HOPPER", "DISPENSER", "DROPPER", "LECTERN", "LEVER",
"DAYLIGHT_DETECTOR", "TRAPPED_CHEST", "TNT", "NOTE_BLOCK", "STONE_BUTTON", "POLISHED_BLACKSTONE_BUTTON",
"OAK_BUTTON", "SPRUCE_BUTTON", "BIRCH_BUTTON", "JUNGLE_BUTTON", "ACACIA_BUTTON", "CHERRY_BUTTON",
"DARK_OAK_BUTTON", "MANGROVE_BUTTON", "BAMBOO_BUTTON", "CRIMSON_BUTTON", "WARPED_BUTTON", "IRON_DOOR", "OAK_DOOR",
"SPRUCE_DOOR", "BIRCH_DOOR", "JUNGLE_DOOR", "ACACIA_DOOR", "CHERRY_DOOR", "DARK_OAK_DOOR", "MANGROVE_DOOR",
"BAMBOO_DOOR", "CRIMSON_DOOR", "WARPED_DOOR", "COPPER_DOOR", "EXPOSED_COPPER_DOOR", "WEATHERED_COPPER_DOOR",
"OXIDIZED_COPPER_DOOR", "WAXED_COPPER_DOOR", "WAXED_EXPOSED_COPPER_DOOR", "WAXED_WEATHERED_COPPER_DOOR",
"WAXED_OXIDIZED_COPPER_DOOR", "IRON_TRAPDOOR", "OAK_TRAPDOOR", "SPRUCE_TRAPDOOR", "BIRCH_TRAPDOOR",
"JUNGLE_TRAPDOOR", "ACACIA_TRAPDOOR", "CHERRY_TRAPDOOR", "DARK_OAK_TRAPDOOR", "MANGROVE_TRAPDOOR",
"BAMBOO_TRAPDOOR", "CRIMSON_TRAPDOOR", "WARPED_TRAPDOOR", "COPPER_TRAPDOOR", "EXPOSED_COPPER_TRAPDOOR",
"WEATHERED_COPPER_TRAPDOOR", "OXIDIZED_COPPER_TRAPDOOR", "WAXED_COPPER_TRAPDOOR", "WAXED_EXPOSED_COPPER_TRAPDOOR",
"WAXED_WEATHERED_COPPER_TRAPDOOR", "WAXED_OXIDIZED_COPPER_TRAPDOOR", "OAK_FENCE_GATE", "SPRUCE_FENCE_GATE",
"BIRCH_FENCE_GATE", "JUNGLE_FENCE_GATE", "ACACIA_FENCE_GATE", "CHERRY_FENCE_GATE", "DARK_OAK_FENCE_GATE",
"MANGROVE_FENCE_GATE", "BAMBOO_FENCE_GATE", "CRIMSON_FENCE_GATE", "WARPED_FENCE_GATE", "STRUCTURE_BLOCK",
"JIGSAW", "OAK_SIGN", "SPRUCE_SIGN", "BIRCH_SIGN", "JUNGLE_SIGN", "ACACIA_SIGN", "CHERRY_SIGN", "DARK_OAK_SIGN",
"MANGROVE_SIGN", "BAMBOO_SIGN", "CRIMSON_SIGN", "WARPED_SIGN", "OAK_HANGING_SIGN", "SPRUCE_HANGING_SIGN",
"BIRCH_HANGING_SIGN", "JUNGLE_HANGING_SIGN", "ACACIA_HANGING_SIGN", "CHERRY_HANGING_SIGN",
"DARK_OAK_HANGING_SIGN", "MANGROVE_HANGING_SIGN", "BAMBOO_HANGING_SIGN", "CRIMSON_HANGING_SIGN",
"WARPED_HANGING_SIGN", "CAKE", "WHITE_BED", "ORANGE_BED", "MAGENTA_BED", "LIGHT_BLUE_BED", "YELLOW_BED",
"LIME_BED", "PINK_BED", "GRAY_BED", "LIGHT_GRAY_BED", "CYAN_BED", "PURPLE_BED", "BLUE_BED", "BROWN_BED",
"GREEN_BED", "RED_BED", "BLACK_BED", "CRAFTER", "BREWING_STAND", "CAULDRON", "FLOWER_POT", "LOOM", "COMPOSTER",
"BARREL", "SMOKER", "BLAST_FURNACE", "CARTOGRAPHY_TABLE", "FLETCHING_TABLE", "GRINDSTONE", "SMITHING_TABLE",
"STONECUTTER", "BELL", "CAMPFIRE", "SOUL_CAMPFIRE", "BEE_NEST", "BEEHIVE", "RESPAWN_ANCHOR", "CANDLE",
"WHITE_CANDLE", "ORANGE_CANDLE", "MAGENTA_CANDLE", "LIGHT_BLUE_CANDLE", "YELLOW_CANDLE", "LIME_CANDLE",
"PINK_CANDLE", "GRAY_CANDLE", "LIGHT_GRAY_CANDLE", "CYAN_CANDLE", "PURPLE_CANDLE", "BLUE_CANDLE", "BROWN_CANDLE",
"GREEN_CANDLE", "RED_CANDLE", "BLACK_CANDLE", "VAULT", "MOVING_PISTON", "REDSTONE_WIRE", "OAK_WALL_SIGN",
"SPRUCE_WALL_SIGN", "BIRCH_WALL_SIGN", "ACACIA_WALL_SIGN", "CHERRY_WALL_SIGN", "JUNGLE_WALL_SIGN",
"DARK_OAK_WALL_SIGN", "MANGROVE_WALL_SIGN", "BAMBOO_WALL_SIGN", "OAK_WALL_HANGING_SIGN",
"SPRUCE_WALL_HANGING_SIGN", "BIRCH_WALL_HANGING_SIGN", "ACACIA_WALL_HANGING_SIGN",
"CHERRY_WALL_HANGING_SIGN", "JUNGLE_WALL_HANGING_SIGN", "DARK_OAK_WALL_HANGING_SIGN",
"MANGROVE_WALL_HANGING_SIGN", "CRIMSON_WALL_HANGING_SIGN", "WARPED_WALL_HANGING_SIGN", "BAMBOO_WALL_HANGING_SIGN",
"WATER_CAULDRON", "LAVA_CAULDRON", "POWDER_SNOW_CAULDRON", "POTTED_TORCHFLOWER", "POTTED_OAK_SAPLING",
"POTTED_SPRUCE_SAPLING", "POTTED_BIRCH_SAPLING", "POTTED_JUNGLE_SAPLING", "POTTED_ACACIA_SAPLING",
"POTTED_CHERRY_SAPLING", "POTTED_DARK_OAK_SAPLING", "POTTED_MANGROVE_PROPAGULE", "POTTED_FERN",
"POTTED_DANDELION", "POTTED_POPPY", "POTTED_BLUE_ORCHID", "POTTED_ALLIUM", "POTTED_AZURE_BLUET",
"POTTED_RED_TULIP", "POTTED_ORANGE_TULIP", "POTTED_WHITE_TULIP", "POTTED_PINK_TULIP", "POTTED_OXEYE_DAISY",
"POTTED_CORNFLOWER", "POTTED_LILY_OF_THE_VALLEY", "POTTED_WITHER_ROSE", "POTTED_RED_MUSHROOM",
"POTTED_BROWN_MUSHROOM", "POTTED_DEAD_BUSH", "POTTED_CACTUS", "POTTED_BAMBOO", "SWEET_BERRY_BUSH",
"CRIMSON_WALL_SIGN", "WARPED_WALL_SIGN", "POTTED_CRIMSON_FUNGUS", "POTTED_WARPED_FUNGUS", "POTTED_CRIMSON_ROOTS",
"POTTED_WARPED_ROOTS", "CANDLE_CAKE", "WHITE_CANDLE_CAKE", "ORANGE_CANDLE_CAKE", "MAGENTA_CANDLE_CAKE",
"LIGHT_BLUE_CANDLE_CAKE", "YELLOW_CANDLE_CAKE", "LIME_CANDLE_CAKE", "PINK_CANDLE_CAKE", "GRAY_CANDLE_CAKE",
"LIGHT_GRAY_CANDLE_CAKE", "CYAN_CANDLE_CAKE", "PURPLE_CANDLE_CAKE", "BLUE_CANDLE_CAKE", "BROWN_CANDLE_CAKE",
"GREEN_CANDLE_CAKE", "RED_CANDLE_CAKE", "BLACK_CANDLE_CAKE", "CAVE_VINES", "CAVE_VINES_PLANT",
"POTTED_AZALEA_BUSH", "POTTED_FLOWERING_AZALEA_BUSH"
);
// @formatter:on
}
private final EventDispatcher eventDispatcher;
private final WorldEdit worldEdit;
private final PlotAreaManager plotAreaManager;
@ -304,19 +236,6 @@ public class PlayerEventListener implements Listener {
this.plotListener = plotListener;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onBlockBreak(final BlockBreakEvent event) {
Location location = BukkitUtil.adapt(event.getBlock().getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = area.getPlot(location);
if (plot != null) {
event.setDropItems(plot.getFlag(TileDropFlag.class));
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerDyeSign(PlayerInteractEvent event) {
ItemStack itemStack = event.getItem();
@ -376,7 +295,7 @@ public class PlayerEventListener implements Listener {
@EventHandler
public void onVehicleEntityCollision(VehicleEntityCollisionEvent e) {
if (e.getVehicle() instanceof Boat) {
if (e.getVehicle().getType() == EntityType.BOAT) {
Location location = BukkitUtil.adapt(e.getEntity().getLocation());
if (location.isPlotArea()) {
if (e.getEntity() instanceof Player) {
@ -593,15 +512,15 @@ public class PlayerEventListener implements Listener {
return;
}
Plot plot = area.getPlot(location);
if (plot != null && !plot.equals(lastPlot)) {
if (plot != null) {
final boolean result = DenyTeleportFlag.allowsTeleport(pp, plot);
// there is one possibility to still allow teleportation:
// 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)))) {
plotListener.plotEntry(pp, plot);
} else {
if (!result && !(plot.getFlag(UntrustedVisitFlag.class) && plot
.getHomeSynchronous()
.equals(BukkitUtil.adaptComplete(to)))) {
pp.sendMessage(
TranslatableCaption.of("deny.no_enter"),
TagResolver.resolver("plot", Tag.inserting(Component.text(plot.toString())))
@ -614,19 +533,6 @@ public class PlayerEventListener implements Listener {
playerMove(event);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onWorldChanged(PlayerChangedWorldEvent event) {
Player player = event.getPlayer();
BukkitPlayer pp = BukkitUtil.adapt(player);
if (this.worldEdit != null) {
if (!pp.hasPermission(Permission.PERMISSION_WORLDEDIT_BYPASS)) {
if (pp.getAttribute("worldedit")) {
pp.removeAttribute("worldedit");
}
}
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void vehicleMove(VehicleMoveEvent event)
throws IllegalAccessException {
@ -966,6 +872,40 @@ public class PlayerEventListener implements Listener {
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onWorldChanged(PlayerChangedWorldEvent event) {
Player player = event.getPlayer();
BukkitPlayer pp = BukkitUtil.adapt(player);
// Delete last location
Plot plot;
try (final MetaDataAccess<Plot> lastPlotAccess =
pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) {
plot = lastPlotAccess.remove();
}
try (final MetaDataAccess<Location> lastLocationAccess =
pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) {
lastLocationAccess.remove();
}
if (plot != null) {
plotListener.plotExit(pp, plot);
}
if (this.worldEdit != null) {
if (!pp.hasPermission(Permission.PERMISSION_WORLDEDIT_BYPASS)) {
if (pp.getAttribute("worldedit")) {
pp.removeAttribute("worldedit");
}
}
}
Location location = pp.getLocation();
PlotArea area = location.getPlotArea();
if (location.isPlotArea()) {
plot = location.getPlot();
if (plot != null) {
plotListener.plotEntry(pp, plot);
}
}
}
@SuppressWarnings("deprecation")
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
@ -1253,7 +1193,7 @@ 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 (blockType.isInteractable()) {
if (!player.isSneaking()) {
break;
}
@ -1738,11 +1678,6 @@ public class PlayerEventListener implements Listener {
return;
}
if (EntityCategories.INTERACTION.contains(entityType) && flagContainer
.getFlag(InteractionInteractFlag.class).getValue()) {
return;
}
if (EntityCategories.VILLAGER.contains(entityType) && flagContainer
.getFlag(VillagerInteractFlag.class).getValue()) {
return;
@ -1986,9 +1921,7 @@ public class PlayerEventListener implements Listener {
@EventHandler
public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) {
Player player = event.getPlayer();
BukkitPlayer pp = BukkitUtil.adapt(player);
Location location = pp.getLocation();
Location location = BukkitUtil.adapt(event.getPlayer().getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
@ -2000,11 +1933,9 @@ public class PlayerEventListener implements Listener {
}
return;
}
if (!plot.isAdded(pp.getUUID())) {
if (plot.getFlag(LecternReadBookFlag.class)) {
plot.debug(event.getPlayer().getName() + " could not take the book because of lectern-read-book = true");
event.setCancelled(true);
}
if (plot.getFlag(LecternReadBookFlag.class)) {
plot.debug(event.getPlayer().getName() + " could not take the book because of lectern-read-book = true");
event.setCancelled(true);
}
}

View File

@ -28,14 +28,12 @@ import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotHandler;
import com.plotsquared.core.plot.flag.implementations.FishingFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.PlotFlagUtil;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
@ -134,11 +132,6 @@ public class ProjectileEventListener implements Listener {
event.setCancelled(true);
}
} else if (!plot.isAdded(pp.getUUID())) {
if (entity instanceof FishHook) {
if (plot.getFlag(FishingFlag.class)) {
return;
}
}
if (!plot.getFlag(ProjectilesFlag.class)) {
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
pp.sendMessage(
@ -194,8 +187,7 @@ public class ProjectileEventListener implements Listener {
return;
}
if (plot.isAdded(pp.getUUID()) || pp.hasPermission(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER) || plot.getFlag(
ProjectilesFlag.class) || (entity instanceof FishHook && plot.getFlag(
FishingFlag.class))) {
ProjectilesFlag.class)) {
return;
}
entity.remove();

View File

@ -49,14 +49,9 @@ public class SingleWorldListener implements Listener {
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod();
} catch (NoSuchMethodException ignored) {
try {
String chunkStatus = PlotSquared.platform().serverVersion()[1] < 21
? "net.minecraft.world.level.chunk" + ".ChunkStatus"
: "net.minecraft.world.level.chunk.status.ChunkStatus";
ReflectionUtils.RefClass classChunkStatus = getRefClass(chunkStatus);
ReflectionUtils.RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus");
this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null);
this.methodGetHandleChunk = classCraftChunk
.getMethod("getHandle", classChunkStatus.getRealClass())
.getRealMethod();
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()).getRealMethod();
} catch (NoSuchMethodException ex) {
throw new RuntimeException(ex);
}
@ -100,8 +95,7 @@ public class SingleWorldListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onChunkLoad(ChunkLoadEvent event) {
// disable this for now, should address https://github.com/IntellectualSites/PlotSquared/issues/4413
// handle(event);
handle(event);
}
}

View File

@ -20,8 +20,6 @@ package com.plotsquared.bukkit.placeholder;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
import com.plotsquared.core.util.query.PlotQuery;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.entity.Player;
@ -85,20 +83,6 @@ public class PAPIPlaceholders extends PlaceholderExpansion {
return String.valueOf(pl.getPlotCount(identifier));
}
if (identifier.startsWith("base_plot_count_")) {
identifier = identifier.substring("base_plot_count_".length());
if (identifier.isEmpty()) {
return "";
}
return String.valueOf(PlotQuery.newQuery()
.ownedBy(pl)
.inWorld(identifier)
.whereBasePlot()
.thatPasses(plot -> !DoneFlag.isDone(plot))
.count());
}
// PlotSquared placeholders
return PlotSquared.platform().placeholderRegistry().getPlaceholderValue(identifier, pl);
}

View File

@ -32,7 +32,6 @@ 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;
import com.sk89q.worldedit.world.item.ItemType;
@ -41,7 +40,6 @@ import io.papermc.lib.PaperLib;
import net.kyori.adventure.audience.Audience;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.WeatherType;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
@ -53,6 +51,7 @@ import org.bukkit.potion.PotionEffectType;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Arrays;
import java.util.Set;
import java.util.UUID;
@ -121,9 +120,6 @@ public class BukkitPlayer extends PlotPlayer<Player> {
@Override
public boolean canTeleport(final @NonNull Location location) {
if (!WorldUtil.isValidLocation(location)) {
return false;
}
final org.bukkit.Location to = BukkitUtil.adapt(location);
final org.bukkit.Location from = player.getLocation();
PlayerTeleportEvent event = new PlayerTeleportEvent(player, from, to);
@ -225,7 +221,7 @@ public class BukkitPlayer extends PlotPlayer<Player> {
@Override
public void teleport(final @NonNull Location location, final @NonNull TeleportCause cause) {
if (!WorldUtil.isValidLocation(location)) {
if (Math.abs(location.getX()) >= 30000000 || Math.abs(location.getZ()) >= 30000000) {
return;
}
final org.bukkit.Location bukkitLocation =
@ -313,21 +309,18 @@ public class BukkitPlayer extends PlotPlayer<Player> {
@Override
public void playMusic(final @NonNull Location location, final @NonNull ItemType id) {
if (id == ItemTypes.AIR) {
if (PlotSquared.platform().serverVersion()[1] >= 19) {
player.stopSound(SoundCategory.MUSIC);
return;
// Let's just stop all the discs because why not?
for (final Sound sound : Arrays.stream(Sound.values())
.filter(sound -> sound.name().contains("DISC")).toList()) {
player.stopSound(sound);
}
// 1.18 and downwards require a specific Sound to stop (even tho the packet does not??)
for (final Sound sound : Sound.values()) {
if (sound.name().startsWith("MUSIC_DISC")) {
this.player.stopSound(sound, SoundCategory.MUSIC);
}
}
return;
// this.player.playEffect(BukkitUtil.getLocation(location), Effect.RECORD_PLAY, Material.AIR);
} else {
// this.player.playEffect(BukkitUtil.getLocation(location), Effect.RECORD_PLAY, id.to(Material.class));
this.player.playSound(BukkitUtil.adapt(location),
Sound.valueOf(BukkitAdapter.adapt(id).name()), Float.MAX_VALUE, 1f
);
}
this.player.playSound(BukkitUtil.adapt(location), Sound.valueOf(BukkitAdapter.adapt(id).name()),
SoundCategory.MUSIC, Float.MAX_VALUE, 1f
);
}
@SuppressWarnings("deprecation") // Needed for Spigot compatibility

View File

@ -30,8 +30,6 @@ import com.plotsquared.core.util.task.TaskTime;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.world.World;
import io.papermc.lib.PaperLib;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.plugin.Plugin;
@ -43,8 +41,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@ -59,8 +55,6 @@ import java.util.function.Consumer;
**/
public final class BukkitChunkCoordinator extends ChunkCoordinator {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + BukkitChunkCoordinator.class.getSimpleName());
private final List<ProgressSubscriber> progressSubscribers = new LinkedList<>();
private final Queue<BlockVector2> requestedChunks;
@ -76,7 +70,6 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator {
private final AtomicInteger expectedSize;
private final AtomicInteger loadingChunks = new AtomicInteger();
private final boolean forceSync;
private final boolean shouldGen;
private int batchSize;
private PlotSquaredTask task;
@ -94,8 +87,7 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator {
@Assisted final @NonNull Consumer<Throwable> throwableConsumer,
@Assisted("unloadAfter") final boolean unloadAfter,
@Assisted final @NonNull Collection<ProgressSubscriber> progressSubscribers,
@Assisted("forceSync") final boolean forceSync,
@Assisted("shouldGen") final boolean shouldGen
@Assisted("forceSync") final boolean forceSync
) {
this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks);
this.availableChunks = new LinkedBlockingQueue<>();
@ -111,7 +103,6 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator {
this.bukkitWorld = Bukkit.getWorld(world.getName());
this.progressSubscribers.addAll(progressSubscribers);
this.forceSync = forceSync;
this.shouldGen = shouldGen;
}
@Override
@ -221,28 +212,18 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator {
* Requests a batch of chunks to be loaded
*/
private void requestBatch() {
for (int i = 0; i < this.batchSize && this.requestedChunks.peek() != null; i++) {
BlockVector2 chunk;
for (int i = 0; i < this.batchSize && (chunk = this.requestedChunks.poll()) != null; i++) {
// This required PaperLib to be bumped to version 1.0.4 to mark the request as urgent
final BlockVector2 chunk = this.requestedChunks.poll();
loadingChunks.incrementAndGet();
PaperLib
.getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), shouldGen, true)
.orTimeout(10L, TimeUnit.SECONDS)
.getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), true, true)
.whenComplete((chunkObject, throwable) -> {
loadingChunks.decrementAndGet();
if (throwable != null) {
if (throwable instanceof TimeoutException) {
LOGGER.warn("Timed out awaiting chunk load {}", chunk);
this.requestedChunks.offer(chunk);
} else {
LOGGER.error("Failed to load chunk {}", chunk, throwable);
// We want one less because this couldn't be processed
this.expectedSize.decrementAndGet();
}
} else if (chunkObject == null) {
if (shouldGen) {
LOGGER.error("Null chunk returned for chunk at {}", chunk);
}
throwable.printStackTrace();
// We want one less because this couldn't be processed
this.expectedSize.decrementAndGet();
} else if (PlotSquared.get().isMainThread(Thread.currentThread())) {
this.processChunk(chunkObject);
} else {

View File

@ -62,28 +62,19 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
private static final SideEffectSet EDGE_LIGHTING_SIDE_EFFECT_SET;
static {
NO_SIDE_EFFECT_SET = enableNetworkIfNeeded()
.with(SideEffect.LIGHTING, SideEffect.State.OFF)
.with(SideEffect.NEIGHBORS, SideEffect.State.OFF);
EDGE_SIDE_EFFECT_SET = NO_SIDE_EFFECT_SET
.with(SideEffect.UPDATE, SideEffect.State.ON)
.with(SideEffect.NEIGHBORS, SideEffect.State.ON);
LIGHTING_SIDE_EFFECT_SET = NO_SIDE_EFFECT_SET
.with(SideEffect.NEIGHBORS, SideEffect.State.OFF);
EDGE_LIGHTING_SIDE_EFFECT_SET = NO_SIDE_EFFECT_SET
.with(SideEffect.UPDATE, SideEffect.State.ON)
.with(SideEffect.NEIGHBORS, SideEffect.State.ON);
}
// make sure block changes are sent
private static SideEffectSet enableNetworkIfNeeded() {
SideEffect network;
try {
network = SideEffect.valueOf("NETWORK");
} catch (IllegalArgumentException ignored) {
return SideEffectSet.none();
}
return SideEffectSet.none().with(network, SideEffect.State.ON);
NO_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.LIGHTING, SideEffect.State.OFF).with(
SideEffect.NEIGHBORS,
SideEffect.State.OFF
);
EDGE_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.UPDATE, SideEffect.State.ON).with(
SideEffect.NEIGHBORS,
SideEffect.State.ON
);
LIGHTING_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.NEIGHBORS, SideEffect.State.OFF);
EDGE_LIGHTING_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.UPDATE, SideEffect.State.ON).with(
SideEffect.NEIGHBORS,
SideEffect.State.ON
);
}
private org.bukkit.World bukkitWorld;
@ -238,7 +229,6 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
.unloadAfter(isUnloadAfter())
.withProgressSubscribers(getProgressSubscribers())
.forceSync(isForceSync())
.shouldGen(isShouldGen())
.build();
return super.enqueue();
}

View File

@ -49,7 +49,6 @@ import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageEvent;
@ -342,7 +341,8 @@ public class BukkitEntityUtil {
}
//disable the firework damage. too much of a headache to support at the moment.
if (vplot != null) {
if (EntityDamageEvent.DamageCause.ENTITY_EXPLOSION == cause && damager instanceof Firework) {
if (EntityDamageEvent.DamageCause.ENTITY_EXPLOSION == cause
&& damager.getType() == EntityType.FIREWORK) {
return false;
}
}

View File

@ -75,7 +75,6 @@ import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Interaction;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.Item;
import org.bukkit.entity.LightningStrike;
@ -262,11 +261,6 @@ public class BukkitUtil extends WorldUtil {
});
}
@Override
public boolean isSmallBlock(Location location) {
return adapt(location).getBlock().getBoundingBox().getHeight() < 0.25;
}
@Override
@NonNegative
public int getHighestBlockSynchronous(final @NonNull String world, final int x, final int z) {
@ -438,7 +432,6 @@ public class BukkitUtil extends WorldUtil {
@Override
public @NonNull Set<com.sk89q.worldedit.world.entity.EntityType> getTypesInCategory(final @NonNull String category) {
final Collection<Class<?>> allowedInterfaces = new HashSet<>();
final int[] version = PlotSquared.platform().serverVersion();
switch (category) {
case "animal" -> {
allowedInterfaces.add(IronGolem.class);
@ -446,7 +439,7 @@ public class BukkitUtil extends WorldUtil {
allowedInterfaces.add(Animals.class);
allowedInterfaces.add(WaterMob.class);
allowedInterfaces.add(Ambient.class);
if (version[1] >= 19) {
if (PlotSquared.platform().serverVersion()[1] >= 19) {
allowedInterfaces.add(Allay.class);
}
}
@ -477,11 +470,6 @@ public class BukkitUtil extends WorldUtil {
allowedInterfaces.add(Firework.class);
}
case "player" -> allowedInterfaces.add(Player.class);
case "interaction" -> {
if ((version[1] > 19) || (version[1] == 19 && version[2] >= 4)) {
allowedInterfaces.add(Interaction.class);
}
}
default -> LOGGER.error("Unknown entity category requested: {}", category);
}
final Set<com.sk89q.worldedit.world.entity.EntityType> types = new HashSet<>();

View File

@ -23,15 +23,11 @@ import com.plotsquared.core.location.World;
import org.bukkit.Bukkit;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.Map;
public class BukkitWorld implements World<org.bukkit.World> {
// Upon world unload we should probably have the P2 BukkitWorld be GCed relatively eagerly, thus freeing the bukkit world.
// We also want to avoid circumstances where a bukkit world has been GCed, but a P2 BukkitWorld has not
private static final Map<String, WeakReference<BukkitWorld>> worldMap = Maps.newHashMap();
private static final Map<String, BukkitWorld> worldMap = Maps.newHashMap();
private static final boolean HAS_MIN_Y;
static {
@ -45,11 +41,10 @@ public class BukkitWorld implements World<org.bukkit.World> {
HAS_MIN_Y = temp;
}
// We want to allow GC to remove bukkit worlds, but not too eagerly
private final SoftReference<org.bukkit.World> world;
private final org.bukkit.World world;
private BukkitWorld(final org.bukkit.World world) {
this.world = new SoftReference<>(world);
this.world = world;
}
/**
@ -73,13 +68,12 @@ public class BukkitWorld implements World<org.bukkit.World> {
* @return World instance
*/
public static @NonNull BukkitWorld of(final org.bukkit.World world) {
WeakReference<BukkitWorld> bukkitWorldRef = worldMap.get(world.getName());
BukkitWorld bukkitWorld;
if (bukkitWorldRef != null && (bukkitWorld = bukkitWorldRef.get()) != null && world.equals(bukkitWorld.world.get())) {
BukkitWorld bukkitWorld = worldMap.get(world.getName());
if (bukkitWorld != null && bukkitWorld.getPlatformWorld().equals(world)) {
return bukkitWorld;
}
bukkitWorld = new BukkitWorld(world);
worldMap.put(world.getName(), new WeakReference<>(bukkitWorld));
worldMap.put(world.getName(), bukkitWorld);
return bukkitWorld;
}
@ -103,26 +97,22 @@ public class BukkitWorld implements World<org.bukkit.World> {
@Override
public org.bukkit.World getPlatformWorld() {
org.bukkit.World world = this.world.get();
if (world == null) {
throw new IllegalStateException("Bukkit platform world was unloaded from memory");
}
return world;
return this.world;
}
@Override
public @NonNull String getName() {
return this.getPlatformWorld().getName();
return this.world.getName();
}
@Override
public int getMinHeight() {
return getMinWorldHeight(getPlatformWorld());
return getMinWorldHeight(world);
}
@Override
public int getMaxHeight() {
return getMaxWorldHeight(getPlatformWorld()) - 1;
return getMaxWorldHeight(world) - 1;
}
@Override

View File

@ -37,9 +37,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.biome.BiomeType;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.Set;
public class FaweRegionManager extends BukkitRegionManager {
@ -61,10 +59,7 @@ public class FaweRegionManager extends BukkitRegionManager {
@Nullable PlotPlayer<?> actor,
@Nullable QueueCoordinator queue
) {
return delegate.setCuboids(
area, regions, blocks, minY, maxY,
Objects.requireNonNullElseGet(queue, area::getQueue).getCompleteTask()
);
return delegate.setCuboids(area, regions, blocks, minY, maxY, queue.getCompleteTask());
}
@Override
@ -116,7 +111,7 @@ public class FaweRegionManager extends BukkitRegionManager {
}
@Override
public boolean regenerateRegion(final @NotNull Location pos1, final @NotNull Location pos2, boolean ignore, final Runnable whenDone) {
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
return delegate.regenerateRegion(pos1, pos2, ignore, whenDone);
}

View File

@ -15,6 +15,11 @@ dependencies {
api(libs.adventureApi)
api(libs.adventureMiniMessage)
// Cloud
api(libs.cloud)
api(libs.cloudMinecraftExtras)
api(libs.cloudRequirements)
// Guice
api(libs.guice) {
exclude(group = "com.google.guava")
@ -68,16 +73,15 @@ tasks {
val isRelease = if (rootProject.version.toString().endsWith("-SNAPSHOT")) "TODO" else rootProject.version.toString()
val opt = options as StandardJavadocDocletOptions
opt.links("https://docs.enginehub.org/javadoc/com.sk89q.worldedit/worldedit-core/" + libs.worldeditCore.get().versionConstraint.toString())
opt.links("https://jd.advntr.dev/api/" + libs.adventureApi.get().versionConstraint.toString())
opt.links("https://jd.advntr.dev/text-minimessage/" + libs.adventureApi.get().versionConstraint.toString())
opt.links("https://jd.advntr.dev/api/4.14.0/")
opt.links("https://jd.advntr.dev/text-minimessage/4.14.0/")
opt.links("https://google.github.io/guice/api-docs/" + libs.guice.get().versionConstraint.toString() + "/javadoc/")
opt.links("https://checkerframework.org/api/")
// opt.links("https://checkerframework.org/api/")
opt.isLinkSource = true
opt.bottom(File("$rootDir/javadocfooter.html").readText())
opt.isUse = true
opt.encoding("UTF-8")
opt.keyWords()
opt.addStringOption("-since", isRelease)
opt.noTimestamp()
}
}

View File

@ -18,7 +18,6 @@
*/
package com.plotsquared.core;
import cloud.commandframework.services.ServicePipeline;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
@ -47,6 +46,7 @@ import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.services.ServicePipeline;
import java.io.File;

View File

@ -206,8 +206,7 @@ public class PlotSquared {
GlobalFlagContainer.setup();
try {
String ver = this.platform.serverNativePackage();
new ReflectionUtils(ver.isEmpty() ? null : ver);
new ReflectionUtils(this.platform.serverNativePackage());
try {
URL logurl = PlotSquared.class.getProtectionDomain().getCodeSource().getLocation();
this.jarFile = new File(
@ -215,7 +214,7 @@ public class PlotSquared {
logurl.toURI().toString().split("\\!")[0].replaceAll("jar:file", "file"))
.getPath());
} catch (URISyntaxException | SecurityException e) {
LOGGER.error(e);
e.printStackTrace();
this.jarFile = new File(this.platform.getDirectory().getParentFile(), "PlotSquared.jar");
if (!this.jarFile.exists()) {
this.jarFile = new File(
@ -239,7 +238,7 @@ public class PlotSquared {
copyFile("skyblock.template", Settings.Paths.TEMPLATES);
showDebug();
} catch (Throwable e) {
LOGGER.error(e);
e.printStackTrace();
}
}
@ -796,8 +795,9 @@ public class PlotSquared {
if (world.equals("CheckingPlotSquaredGenerator")) {
return;
}
// Don't check the return result -> breaks runtime loading of single plot areas on creation
this.getPlotAreaManager().addWorld(world);
if (!this.getPlotAreaManager().addWorld(world)) {
return;
}
Set<String> worlds;
if (this.worldConfiguration.contains("worlds")) {
worlds = this.worldConfiguration.getConfigurationSection("worlds").getKeys(false);

View File

@ -184,7 +184,6 @@ public class Area extends SubCommand {
CuboidRegion.makeCuboid(playerSelectedRegion)
).length != 0) {
player.sendMessage(TranslatableCaption.of("single.single_area_overlapping"));
return false;
}
// Alter the region
final BlockVector3 playerSelectionMin = playerSelectedRegion.getMinimumPoint();

View File

@ -18,7 +18,6 @@
*/
package com.plotsquared.core.command;
import cloud.commandframework.services.ServicePipeline;
import com.google.inject.Inject;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings;
@ -49,6 +48,7 @@ import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.services.ServicePipeline;
import java.util.Collections;
import java.util.Iterator;
@ -332,7 +332,7 @@ public class Auto extends SubCommand {
List<Plot> plots = this.servicePipeline
.pump(new AutoQuery(player, null, sizeX, sizeZ, plotarea))
.through(AutoService.class)
.getResult();
.complete();
plots = this.eventDispatcher.callAutoPlotsChosen(player, plots).getPlots();

View File

@ -21,9 +21,8 @@ package com.plotsquared.core.command;
import com.google.inject.Inject;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.events.PlayerBuyPlotEvent;
import com.plotsquared.core.events.PlotFlagRemoveEvent;
import com.plotsquared.core.events.Result;
import com.plotsquared.core.player.OfflinePlotPlayer;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
@ -89,30 +88,22 @@ public class Buy extends Command {
TranslatableCaption.of("permission.cant_claim_more_plots"),
TagResolver.resolver("amount", Tag.inserting(Component.text(player.getAllowedPlots())))
);
double priceFlag = plot.getFlag(PriceFlag.class);
if (priceFlag <= 0) {
double price = plot.getFlag(PriceFlag.class);
if (price <= 0) {
throw new CommandException(TranslatableCaption.of("economy.not_for_sale"));
}
checkTrue(
this.econHandler.isSupported(),
TranslatableCaption.of("economy.vault_or_consumer_null")
);
PlayerBuyPlotEvent event = this.eventDispatcher.callPlayerBuyPlot(player, plot, priceFlag);
if (event.getEventResult() == Result.DENY) {
throw new CommandException(TranslatableCaption.of("economy.cannot_buy_blocked"));
}
double price = event.getEventResult() == Result.FORCE ? 0 : event.price();
if (this.econHandler.getMoney(player) < price) {
throw new CommandException(
TranslatableCaption.of("economy.cannot_afford_plot"),
TagResolver.builder()
.tag("money", Tag.inserting(Component.text(this.econHandler.format(price))))
.tag("balance", Tag.inserting(Component.text(this.econHandler.format(this.econHandler.getMoney(player)))))
.build()
);
}
checkTrue(
this.econHandler.getMoney(player) >= price,
TranslatableCaption.of("economy.cannot_afford_plot"),
TagResolver.builder()
.tag("money", Tag.inserting(Component.text(this.econHandler.format(price))))
.tag("balance", Tag.inserting(Component.text(this.econHandler.format(this.econHandler.getMoney(player)))))
.build()
);
this.econHandler.withdrawMoney(player, price);
// Failure
// Success
@ -122,8 +113,7 @@ public class Buy extends Command {
TagResolver.resolver("money", Tag.inserting(Component.text(this.econHandler.format(price))))
);
OfflinePlotPlayer previousOwner = PlotSquared.platform().playerManager().getOfflinePlayer(plot.getOwnerAbs());
this.econHandler.depositMoney(previousOwner, price);
this.econHandler.depositMoney(PlotSquared.platform().playerManager().getOfflinePlayer(plot.getOwnerAbs()), price);
PlotPlayer<?> owner = PlotSquared.platform().playerManager().getPlayerIfExists(plot.getOwnerAbs());
if (owner != null) {
@ -137,17 +127,16 @@ public class Buy extends Command {
);
}
PlotFlag<?, ?> plotFlag = plot.getFlagContainer().getFlag(PriceFlag.class);
if (this.eventDispatcher.callFlagRemove(plotFlag, plot).getEventResult() != Result.DENY) {
plot.removeFlag(plotFlag);
PlotFlagRemoveEvent event = this.eventDispatcher.callFlagRemove(plotFlag, plot);
if (event.getEventResult() != Result.DENY) {
plot.removeFlag(event.getFlag());
}
plot.setOwner(player.getUUID());
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);
whenDone.run(Buy.this, CommandResult.SUCCESS);
}, () -> {
this.econHandler.depositMoney(player, price);

View File

@ -131,12 +131,10 @@ 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()
);
this.eventDispatcher.callPostPlotClear(player, plot);
}));
if (!result) {
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));

View File

@ -124,7 +124,6 @@ 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);

View File

@ -20,6 +20,7 @@ package com.plotsquared.core.command;
import com.google.inject.Inject;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.StaticCaption;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
@ -201,6 +202,7 @@ public class Download extends SubCommand {
.tag("delete", Tag.preProcessParsed("Not available"))
.build()
);
player.sendMessage(StaticCaption.of(value.toString()));
}
}
));

View File

@ -153,7 +153,7 @@ public class Kick extends SubCommand {
if (plot == null) {
return Collections.emptyList();
}
return TabCompletions.completePlayersInPlot(player, plot, String.join(",", args).trim(),
return TabCompletions.completePlayersInPlot(plot, String.join(",", args).trim(),
Collections.singletonList(player.getName())
);
}

View File

@ -44,13 +44,8 @@ import org.apache.logging.log4j.Logger;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* PlotSquared command class.
*/
@ -152,7 +147,8 @@ public class MainCommand extends Command {
try {
injector.getInstance(command);
} catch (final Exception e) {
LOGGER.error("Failed to register command {}", command.getCanonicalName(), e);
LOGGER.error("Failed to register command {}", command.getCanonicalName());
e.printStackTrace();
}
}
@ -240,171 +236,110 @@ public class MainCommand extends Command {
RunnableVal3<Command, Runnable, Runnable> confirm,
RunnableVal2<Command, CommandResult> whenDone
) {
prepareArguments(new CommandExecutionData(player, args, confirm, whenDone, null))
.thenCompose(executionData -> {
if (executionData.isEmpty()) {
return CompletableFuture.completedFuture(false);
// Optional command scope //
Location location = null;
Plot plot = null;
boolean tp = false;
if (args.length >= 2) {
PlotArea area = player.getApplicablePlotArea();
Plot newPlot = Plot.fromString(area, args[0]);
if (newPlot != null && (player instanceof ConsolePlayer || newPlot.getArea()
.equals(area) || player.hasPermission(Permission.PERMISSION_ADMIN)
|| player.hasPermission(Permission.PERMISSION_ADMIN_AREA_SUDO))
&& !newPlot.isDenied(player.getUUID())) {
final Location newLoc;
if (newPlot.getArea() instanceof SinglePlotArea) {
newLoc = newPlot.isLoaded() ? newPlot.getCenterSynchronous() : Location.at("", 0, 0, 0);
} else {
newLoc = newPlot.getCenterSynchronous();
}
if (player.canTeleport(newLoc)) {
// Save meta
try (final MetaDataAccess<Location> locationMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) {
location = locationMetaDataAccess.get().orElse(null);
locationMetaDataAccess.set(newLoc);
}
var data = executionData.get();
try {
return super.execute(data.player(), data.args(), data.confirm(), data.whenDone());
} catch (CommandException e) {
throw e;
} catch (Throwable e) {
LOGGER.error("A error occurred while executing plot command", e);
String message = e.getMessage();
if (message != null) {
data.player().sendMessage(
TranslatableCaption.of("errors.error"),
TagResolver.resolver("value", Tag.inserting(Component.text(message)))
);
} else {
data.player().sendMessage(
TranslatableCaption.of("errors.error_console"));
}
} finally {
if (data.postCommandData() != null) {
resetCommandScope(data.player(), data.postCommandData());
}
try (final MetaDataAccess<Plot> plotMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) {
plot = plotMetaDataAccess.get().orElse(null);
plotMetaDataAccess.set(newPlot);
}
return CompletableFuture.completedFuture(true);
});
tp = true;
} else {
player.sendMessage(TranslatableCaption.of("border.denied"));
}
// Trim command
args = Arrays.copyOfRange(args, 1, args.length);
}
if (args.length >= 2 && !args[0].isEmpty() && args[0].charAt(0) == '-') {
if ("f".equals(args[0].substring(1))) {
confirm = new RunnableVal3<>() {
@Override
public void run(Command cmd, Runnable success, Runnable failure) {
if (area != null && PlotSquared.platform().econHandler().isEnabled(area)) {
PlotExpression priceEval =
area.getPrices().get(cmd.getFullId());
double price = priceEval != null ? priceEval.evaluate(0d) : 0d;
if (price != 0d
&& PlotSquared.platform().econHandler().getMoney(player) < price) {
if (failure != null) {
failure.run();
}
return;
}
}
if (success != null) {
success.run();
}
}
};
args = Arrays.copyOfRange(args, 1, args.length);
} else {
player.sendMessage(TranslatableCaption.of("errors.invalid_command_flag"));
return CompletableFuture.completedFuture(false);
}
}
}
try {
super.execute(player, args, confirm, whenDone);
} catch (CommandException e) {
throw e;
} catch (Throwable e) {
e.printStackTrace();
String message = e.getMessage();
if (message != null) {
player.sendMessage(
TranslatableCaption.of("errors.error"),
TagResolver.resolver("value", Tag.inserting(Component.text(message)))
);
} else {
player.sendMessage(
TranslatableCaption.of("errors.error_console"));
}
}
// Reset command scope //
if (tp && !(player instanceof ConsolePlayer)) {
try (final MetaDataAccess<Location> locationMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) {
if (location == null) {
locationMetaDataAccess.remove();
} else {
locationMetaDataAccess.set(location);
}
}
try (final MetaDataAccess<Plot> plotMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) {
if (plot == null) {
plotMetaDataAccess.remove();
} else {
plotMetaDataAccess.set(plot);
}
}
}
return CompletableFuture.completedFuture(true);
}
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]);
return preparePlotArgument(newPlot, data, area)
.thenApply(d -> d.flatMap(x -> prepareFlagArgument(x, area)));
} else {
return CompletableFuture.completedFuture(Optional.of(data));
}
}
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
));
});
}
return CompletableFuture.completedFuture(Optional.of(data));
}
private Optional<CommandExecutionData> prepareFlagArgument(@Nonnull CommandExecutionData data, @Nonnull PlotArea area) {
if (data.args().length >= 2 && !data.args()[0].isEmpty() && data.args()[0].charAt(0) == '-') {
if ("f".equals(data.args()[0].substring(1))) {
return Optional.of(new CommandExecutionData(
data.player(),
Arrays.copyOfRange(data.args(), 1, data.args().length), // Trimmed command
createForcedConfirmation(data.player(), area),
data.whenDone(),
data.postCommandData()
));
} else {
data.player().sendMessage(TranslatableCaption.of("errors.invalid_command_flag"));
return Optional.empty();
}
}
return Optional.of(data);
}
private CompletableFuture<Location> fetchPlotCenterLocation(Plot plot) {
if (plot.getArea() instanceof SinglePlotArea && !plot.isLoaded()) {
return CompletableFuture.completedFuture(Location.at("", 0, 0, 0));
}
CompletableFuture<Location> future = new CompletableFuture<>();
plot.getCenter(future::complete);
return future;
}
private @Nonnull RunnableVal3<Command, Runnable, Runnable> createForcedConfirmation(@Nonnull PlotPlayer<?> player,
@Nullable PlotArea area) {
return new RunnableVal3<>() {
@Override
public void run(Command cmd, Runnable success, Runnable failure) {
if (area != null && PlotSquared.platform().econHandler().isEnabled(area)
&& Optional.of(area.getPrices().get(cmd.getFullId()))
.map(priceEval -> priceEval.evaluate(0d))
.filter(price -> price != 0d)
.filter(price -> PlotSquared.platform().econHandler().getMoney(player) < price)
.isPresent()) {
if (failure != null) {
failure.run();
}
return;
}
if (success != null) {
success.run();
}
}
};
}
private @Nonnull TemporaryCommandMeta setCommandScope(@Nonnull PlotPlayer<?> player, @Nonnull TemporaryCommandMeta commandMeta) {
Objects.requireNonNull(commandMeta.location());
Objects.requireNonNull(commandMeta.plot());
Location location;
Plot plot;
try (final MetaDataAccess<Location> locationMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) {
location = locationMetaDataAccess.get().orElse(null);
locationMetaDataAccess.set(commandMeta.location());
}
try (final MetaDataAccess<Plot> plotMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) {
plot = plotMetaDataAccess.get().orElse(null);
plotMetaDataAccess.set(commandMeta.plot());
}
return new TemporaryCommandMeta(location, plot);
}
private void resetCommandScope(@Nonnull PlotPlayer<?> player, @Nonnull TemporaryCommandMeta commandMeta) {
try (final MetaDataAccess<Location> locationMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) {
if (commandMeta.location() == null) {
locationMetaDataAccess.remove();
} else {
locationMetaDataAccess.set(commandMeta.location());
}
}
try (final MetaDataAccess<Plot> plotMetaDataAccess
= player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) {
if (commandMeta.plot() == null) {
plotMetaDataAccess.remove();
} else {
plotMetaDataAccess.set(commandMeta.plot());
}
}
}
private record CommandExecutionData(@Nonnull PlotPlayer<?> player, @Nonnull String[] args,
@Nonnull RunnableVal3<Command, Runnable, Runnable> confirm,
@Nonnull RunnableVal2<Command, CommandResult> whenDone,
@Nullable TemporaryCommandMeta postCommandData) {}
private record TemporaryCommandMeta(@Nullable Location location, @Nullable Plot plot) {}
@Override
public boolean canExecute(PlotPlayer<?> player, boolean message) {
return true;

View File

@ -56,13 +56,9 @@ public class Music extends SubCommand {
.asList("music_disc_13", "music_disc_cat", "music_disc_blocks", "music_disc_chirp",
"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_pigstep", "music_disc_5", "music_disc_relic"
);
// make sure all discs and the bedrock ("cancel") fit into the inventory
private static final int INVENTORY_ROWS = (int) Math.ceil((DISCS.size() + 1) / 9.0);
private final InventoryUtil inventoryUtil;
private final EventDispatcher eventDispatcher;
@ -97,7 +93,7 @@ public class Music extends SubCommand {
PlotInventory inv = new PlotInventory(
this.inventoryUtil,
player,
INVENTORY_ROWS,
2,
TranslatableCaption.of("plotjukebox.jukebox_header").getComponent(player)
) {
@Override

View File

@ -117,8 +117,8 @@ public class Remove extends SubCommand {
}
if (count == 0) {
player.sendMessage(
TranslatableCaption.of("member.player_not_removed"),
TagResolver.resolver("player", Tag.inserting(Component.text(args[0])))
TranslatableCaption.of("errors.invalid_player"),
TagResolver.resolver("value", Tag.inserting(Component.text(args[0])))
);
} else {
player.sendMessage(

View File

@ -77,7 +77,6 @@ public class Visit extends Command {
query.whereBasePlot();
}
// without specified argument
if (page == Integer.MIN_VALUE) {
page = 1;
}
@ -95,15 +94,10 @@ public class Visit extends Command {
final List<Plot> plots = query.asList();
// Conversion of reversed page argument
if (page < 0) {
page = (plots.size() + 1) + page;
}
if (plots.isEmpty()) {
player.sendMessage(TranslatableCaption.of("invalid.found_no_plots"));
return;
} else if (page > plots.size() || page < 1) {
} else if (plots.size() < page || page < 1) {
player.sendMessage(
TranslatableCaption.of("invalid.number_not_in_range"),
TagResolver.builder()
@ -194,22 +188,34 @@ public class Visit extends Command {
int page = Integer.MIN_VALUE;
switch (args.length) {
// /p v <player> <area> <page>
// /p v <user> <area> <page>
case 3:
if (isInvalidPageNr(args[2])) {
sendInvalidPageNrMsg(player);
if (!MathMan.isInteger(args[2])) {
player.sendMessage(
TranslatableCaption.of("invalid.not_valid_number"),
TagResolver.resolver("value", Tag.inserting(Component.text("(1, ∞)")))
);
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
TagResolver.resolver("value", Tag.inserting(Component.text(getUsage())))
);
return CompletableFuture.completedFuture(false);
}
page = getPageNr(args[2]);
// /p v <player> <area> [page]
// /p v <player> [page]
page = Integer.parseInt(args[2]);
// /p v <name> <area> [page]
// /p v <name> [page]
case 2:
// If "case 3" is already through or the argument is not a page number:
// -> /p v <player> <area> [page]
if (page != Integer.MIN_VALUE || isInvalidPageNr(args[1])) {
if (page != Integer.MIN_VALUE || !MathMan.isInteger(args[1])) {
sortByArea = this.plotAreaManager.getPlotAreaByString(args[1]);
if (sortByArea == null) {
sendInvalidPageNrMsg(player);
player.sendMessage(
TranslatableCaption.of("invalid.not_valid_number"),
TagResolver.resolver("value", Tag.inserting(Component.text("(1, ∞)")))
);
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
TagResolver.resolver("value", Tag.inserting(Component.text(getUsage())))
);
return CompletableFuture.completedFuture(false);
}
@ -243,13 +249,16 @@ public class Visit extends Command {
});
break;
}
// -> /p v <player> <page>
if (isInvalidPageNr(args[1])) {
sendInvalidPageNrMsg(player);
try {
page = Integer.parseInt(args[1]);
} catch (NumberFormatException ignored) {
player.sendMessage(
TranslatableCaption.of("invalid.not_a_number"),
TagResolver.resolver("value", Tag.inserting(Component.text(args[1])))
);
return CompletableFuture.completedFuture(false);
}
page = getPageNr(args[1]);
// /p v <player> [page]
// /p v <name> [page]
// /p v <uuid> [page]
// /p v <plot> [page]
// /p v <alias>
@ -317,35 +326,6 @@ public class Visit extends Command {
return CompletableFuture.completedFuture(true);
}
private boolean isInvalidPageNr(String arg) {
if (MathMan.isInteger(arg)) {
return false;
} else if (arg.equals("last") || arg.equals("n")) {
return false;
}
return true;
}
private int getPageNr(String arg) {
if (MathMan.isInteger(arg)) {
return Integer.parseInt(arg);
} else if (arg.equals("last") || arg.equals("n")) {
return -1;
}
return Integer.MIN_VALUE;
}
private void sendInvalidPageNrMsg(PlotPlayer<?> player) {
player.sendMessage(
TranslatableCaption.of("invalid.not_valid_number"),
TagResolver.resolver("value", Tag.inserting(Component.text("(1, ∞)")))
);
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
TagResolver.resolver("value", Tag.inserting(Component.text(getUsage())))
);
}
@Override
public Collection<Command> tab(PlotPlayer<?> player, String[] args, boolean space) {
final List<Command> completions = new ArrayList<>();
@ -354,7 +334,6 @@ public class Visit extends Command {
case 1 -> {
completions.addAll(
TabCompletions.completeAreas(args[1]));
completions.addAll(TabCompletions.asCompletions("last"));
if (args[1].isEmpty()) {
// if no input is given, only suggest 1 - 3
completions.addAll(
@ -365,7 +344,6 @@ public class Visit extends Command {
TabCompletions.completeNumbers(args[1], 10, 999));
}
case 2 -> {
completions.addAll(TabCompletions.asCompletions("last"));
if (args[2].isEmpty()) {
// if no input is given, only suggest 1 - 3
completions.addAll(

View File

@ -0,0 +1,98 @@
/*
* 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.commands;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
import io.leangen.geantyref.TypeToken;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.processors.requirements.Requirement;
import org.incendo.cloud.processors.requirements.Requirements;
import java.util.List;
/**
* Something that is required for a command to be executed.
*/
public interface CommandRequirement extends Requirement<PlotPlayer<?>, CommandRequirement> {
/**
* The key used to store the requirements in the {@link org.incendo.cloud.meta.CommandMeta}.
*/
CloudKey<Requirements<PlotPlayer<?>, CommandRequirement>> REQUIREMENTS_KEY = CloudKey.of(
"requirements",
new TypeToken<Requirements<PlotPlayer<?>, CommandRequirement>>() {
}
);
/**
* Returns the caption sent when the requirement is not met.
*
* @return the caption
*/
@NonNull TranslatableCaption failureCaption();
/**
* Returns the placeholder values.
*
* @return placeholder values
*/
default @NonNull TagResolver @NonNull[] tagResolvers() {
return new TagResolver[0];
}
/**
* Returns a requirement that evaluates to {@code true} if the sender has the given {@code permission} or if
* this requirement evaluates to {@code true}.
*
* @param permission the override permission
* @return the new requirement
*/
default @NonNull CommandRequirement withPermissionOverride(final @NonNull Permission permission) {
final CommandRequirement thisRequirement = this;
return new CommandRequirement() {
@Override
public @NonNull TranslatableCaption failureCaption() {
return TranslatableCaption.of("permission.no_permission");
}
@Override
public @NonNull TagResolver @NonNull [] tagResolvers() {
return new TagResolver[] {
TagResolver.resolver("node", Tag.inserting(Permission.PERMISSION_SET_FLAG_OTHER))
};
}
@Override
public @NonNull List<@NonNull CommandRequirement> parents() {
return thisRequirement.parents();
}
@Override
public boolean evaluateRequirement(final @NonNull CommandContext<PlotPlayer<?>> context) {
return context.sender().hasPermission(permission) || thisRequirement.evaluateRequirement(context);
}
};
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.commands;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.PlotPlayer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
* Common {@link CommandRequirement command requirements}.
*/
public enum CommonCommandRequirement implements CommandRequirement {
/**
* Requires that the command sender is currently in a plot.
*/
REQUIRES_PLOT(TranslatableCaption.of("errors.not_in_plot"), ctx -> ctx.sender().getCurrentPlot() != null),
/**
* Requires that the command sender is in a claimed plot.
*/
REQUIRES_OWNER(TranslatableCaption.of("working.plot_not_claimed"),
ctx -> ctx.sender().getCurrentPlot().hasOwner(),
REQUIRES_PLOT
),
/**
* Requires that the command sender is the plot owner.
*/
IS_OWNER(TranslatableCaption.of("permission.no_plot_perms"),
ctx -> ctx.sender().getCurrentPlot().isOwner(ctx.sender().getUUID()),
REQUIRES_OWNER
)
;
private final TranslatableCaption failureCaption;
private final Predicate<CommandContext<PlotPlayer<?>>> predicate;
private final List<@NonNull CommandRequirement> parents;
CommonCommandRequirement(
final @NonNull TranslatableCaption failureCaption,
final @NonNull Predicate<CommandContext<PlotPlayer<?>>> predicate,
final @NonNull CommandRequirement @NonNull... parents
) {
this.failureCaption = failureCaption;
this.predicate = predicate;
this.parents = Arrays.asList(parents);
}
public @NonNull TranslatableCaption failureCaption() {
return this.failureCaption;
}
@Override
public @NonNull List<@NonNull CommandRequirement> parents() {
return this.parents;
}
@Override
public boolean evaluateRequirement(final @NonNull CommandContext<PlotPlayer<?>> context) {
return this.predicate.test(context);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.commands;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.caption.CaptionMap;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.PlotPlayer;
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;
import org.incendo.cloud.caption.Caption;
import org.incendo.cloud.caption.CaptionProvider;
/**
* {@link CaptionProvider} that retrieves caption values from the {@link CaptionMap caption map}.
*/
public final class PlotSquaredCaptionProvider implements CaptionProvider<PlotPlayer<?>> {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PlotSquaredCaptionProvider.class.getSimpleName());
@Override
public @Nullable String provide(final @NonNull Caption caption, final @NonNull PlotPlayer<?> recipient) {
try {
return PlotSquared.get()
.getCaptionMap(TranslatableCaption.DEFAULT_NAMESPACE)
.getMessage(TranslatableCaption.of(caption.key()), recipient);
} catch (final CaptionMap.NoSuchCaptionException ignored) {
LOGGER.warn("Missing caption '{}', will attempt to fall back on Cloud defaults", caption.key());
return null;
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.commands;
import com.plotsquared.core.command.CommandCategory;
import com.plotsquared.core.player.PlotPlayer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bean.CommandBean;
import org.incendo.cloud.bean.CommandProperties;
import org.incendo.cloud.processors.requirements.RequirementApplicable;
import org.incendo.cloud.processors.requirements.Requirements;
import java.util.List;
public abstract class PlotSquaredCommandBean extends CommandBean<PlotPlayer<?>> {
private final RequirementApplicable.RequirementApplicableFactory<PlotPlayer<?>, CommandRequirement>
requirementApplicableFactory = RequirementApplicable.factory(CommandRequirement.REQUIREMENTS_KEY);
/**
* Returns the category of the command.
*
* @return the category
*/
public abstract @NonNull CommandCategory category();
/**
* Returns the requirements for the command to be executable.
*
* @return the requirements
*/
public abstract @NonNull List<@NonNull CommandRequirement> requirements();
/**
* Prepares the given {@code builder}.
*
* <p>This should be implemented by abstract classes that extend {@link PlotSquaredCommandBean} to offer shared behavior
* for a subset of plot commands.</p>
*
* @param builder the builder
* @return the prepared builder
*/
protected Command.@NonNull Builder<PlotPlayer<?>> prepare(final Command.@NonNull Builder<PlotPlayer<?>> builder) {
return builder;
}
@Override
protected final @NonNull CommandProperties properties() {
return CommandProperties.of("platsquared", "plat");
}
@Override
protected final Command.@NonNull Builder<PlotPlayer<?>> configure(final Command.@NonNull Builder<PlotPlayer<?>> builder) {
return this.configurePlotCommand(this.prepare(builder.meta(PlotSquaredCommandMeta.META_CATEGORY, this.category())))
.apply(this.requirementApplicableFactory.create(Requirements.of(this.requirements())));
}
protected abstract Command.@NonNull Builder<PlotPlayer<?>> configurePlotCommand(
Command.@NonNull Builder<PlotPlayer<?>> builder
);
}

View File

@ -0,0 +1,74 @@
/*
* 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.commands;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.plotsquared.core.commands.injection.PlotInjector;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.injection.GuiceInjectionService;
import java.util.Set;
@Singleton
public final class PlotSquaredCommandManager {
private final CommandManager<PlotPlayer<?>> commandManager;
private final Injector injector;
@Inject
public PlotSquaredCommandManager(
final @NonNull CommandManager<PlotPlayer<?>> commandManager,
final @NonNull Injector injector
) {
this.commandManager = commandManager;
this.injector = injector;
this.registerInjectors();
}
/**
* Registers the commands that are shipped with PlotSquared.
*/
public void registerDefaultCommands() {
final Set<PlotSquaredCommandBean> commands =
this.injector.getInstance(Key.get(new TypeLiteral<Set<PlotSquaredCommandBean>>() {}));
commands.forEach(command -> this.commandManager().command(command));
}
/**
* Returns the command manager.
*
* @return the command manager
*/
public @NonNull CommandManager<PlotPlayer<?>> commandManager() {
return this.commandManager;
}
private void registerInjectors() {
this.commandManager.parameterInjectorRegistry().registerInjector(Plot.class,
this.injector.getInstance(PlotInjector.class));
this.commandManager.parameterInjectorRegistry().registerInjectionService(GuiceInjectionService.create(this.injector));
}
}

View File

@ -16,28 +16,21 @@
* 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.events.post;
package com.plotsquared.core.commands;
import com.plotsquared.core.events.PlotPlayerEvent;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.command.CommandCategory;
import org.incendo.cloud.key.CloudKey;
/**
* Called after a {@link Plot} was cleared.
*
* @since 7.3.2
* Shared {@link org.incendo.cloud.meta.CommandMeta command meta} keys.
*/
public class PostPlotClearEvent extends PlotPlayerEvent {
public final class PlotSquaredCommandMeta {
/**
* Instantiate a new PostPlotClearEvent.
*
* @param plotPlayer The {@link PlotPlayer} that initiated the clear.
* @param plot The clearing plot.
* Key that determines what {@link CommandCategory category} a command belongs to.
*/
public PostPlotClearEvent(final PlotPlayer<?> plotPlayer, final Plot plot) {
super(plotPlayer, plot);
}
public static final CloudKey<CommandCategory> META_CATEGORY = CloudKey.of("category", CommandCategory.class);
private PlotSquaredCommandMeta() {
}
}

View File

@ -16,24 +16,20 @@
* 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.plot.flag.implementations;
package com.plotsquared.core.commands;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.plot.flag.types.BooleanFlag;
import com.plotsquared.core.player.PlotPlayer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.processors.requirements.RequirementFailureHandler;
public class FishingFlag extends BooleanFlag<FishingFlag> {
public static final FishingFlag FISHING_TRUE = new FishingFlag(true);
public static final FishingFlag FISHING_FALSE = new FishingFlag(false);
private FishingFlag(boolean value) {
super(value, TranslatableCaption.of("flags.flag_description_fishing"));
}
public final class PlotSquaredRequirementFailureHandler implements RequirementFailureHandler<PlotPlayer<?>, CommandRequirement> {
@Override
protected FishingFlag flagOf(@NonNull final Boolean value) {
return value ? FISHING_TRUE : FISHING_FALSE;
public void handleFailure(
final @NonNull CommandContext<PlotPlayer<?>> context,
final @NonNull CommandRequirement requirement
) {
context.sender().sendMessage(requirement.failureCaption(), requirement.tagResolvers());
}
}

View File

@ -0,0 +1,120 @@
/*
* 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.commands.command.setting.flag;
import com.google.inject.Inject;
import com.plotsquared.core.commands.parser.PlotFlagParser;
import com.plotsquared.core.commands.suggestions.FlagValueSuggestionProvider;
import com.plotsquared.core.configuration.caption.CaptionUtility;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.events.PlotFlagAddEvent;
import com.plotsquared.core.events.Result;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.FlagParseException;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.util.EventDispatcher;
import io.leangen.geantyref.TypeToken;
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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import static com.plotsquared.core.commands.parser.PlotFlagParser.plotFlagParser;
import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser;
public final class FlagAddCommand extends FlagCommandBean {
private static final CloudKey<PlotFlag<?, ?>> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken<PlotFlag<?, ?>>() {});
private static final CloudKey<String> COMPONENT_VALUE = CloudKey.of("value", String.class);
private final EventDispatcher eventDispatcher;
@Inject
public FlagAddCommand(final @NonNull EventDispatcher eventDispatcher) {
this.eventDispatcher = eventDispatcher;
}
@Override
protected Command.@NonNull Builder<PlotPlayer<?>> configurePlotCommand(
final Command.@NonNull Builder<PlotPlayer<?>> builder
) {
return builder.literal("add")
.required(COMPONENT_FLAG, plotFlagParser(PlotFlagParser.FlagSource.GLOBAL))
.required(COMPONENT_VALUE, greedyStringParser(), new FlagValueSuggestionProvider(COMPONENT_FLAG));
}
@Override
public void execute(final @NonNull CommandContext<PlotPlayer<?>> commandContext) {
final PlotPlayer<?> player = commandContext.sender();
final Plot plot = commandContext.inject(Plot.class).orElseThrow();
final PlotFlag<?, ?> flag = commandContext.get(COMPONENT_FLAG);
final String flagValue = commandContext.get(COMPONENT_VALUE);
final PlotFlagAddEvent event = this.eventDispatcher.callFlagAdd(flag, plot);
if (event.getEventResult() == Result.DENY) {
player.sendMessage(
TranslatableCaption.of("events.event_denied"),
TagResolver.resolver("value", Tag.inserting(Component.text("Flag set")))
);
return;
}
if (event.getEventResult() != Result.FORCE) {
final String[] split = flagValue.split(",");
for (final String entry : split) {
if (!checkPermValue(player, flag, flag.getName(), entry)) {
return;
}
}
}
final String sanitizedValue = CaptionUtility.stripClickEvents(flag, flagValue);
final PlotFlag<?, ?> parsedFlag;
try {
parsedFlag = flag.parse(flagValue);
} catch (final FlagParseException e) {
player.sendMessage(
TranslatableCaption.of("flag.flag_parse_error"),
TagResolver.builder()
.tag("flag_name", Tag.inserting(Component.text(flag.getName())))
.tag("flag_value", Tag.inserting(Component.text(e.getValue())))
.tag("error", Tag.inserting(e.getErrorMessage().toComponent(player)))
.build()
);
return;
}
final boolean result = plot.setFlag(plot.getFlagContainer().getFlag(flag.getClass()).merge(parsedFlag.getValue()));
if (!result) {
player.sendMessage(TranslatableCaption.of("flag.flag_not_added"));
return;
}
player.sendMessage(
TranslatableCaption.of("flag.flag_added"),
TagResolver.builder()
.tag("flag", Tag.inserting(Component.text(flag.getName())))
.tag("value", Tag.inserting(Component.text(parsedFlag.toString())))
.build()
);
}
}

View File

@ -0,0 +1,139 @@
/*
* 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.commands.command.setting.flag;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.command.CommandCategory;
import com.plotsquared.core.commands.CommandRequirement;
import com.plotsquared.core.commands.CommonCommandRequirement;
import com.plotsquared.core.commands.PlotSquaredCommandBean;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.flag.FlagParseException;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.plot.flag.types.IntegerFlag;
import com.plotsquared.core.plot.flag.types.ListFlag;
import com.plotsquared.core.util.MathMan;
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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import java.util.List;
public abstract class FlagCommandBean extends PlotSquaredCommandBean {
protected static boolean checkPermValue(
final @NonNull PlotPlayer<?> player,
final @NonNull PlotFlag<?, ?> flag, @NonNull String key, @NonNull String value
) {
key = key.toLowerCase();
value = value.toLowerCase();
String perm = Permission.PERMISSION_SET_FLAG_KEY_VALUE.format(key.toLowerCase(), value.toLowerCase());
if (flag instanceof IntegerFlag && MathMan.isInteger(value)) {
try {
int numeric = Integer.parseInt(value);
// Getting full permission without ".<amount>" at the end
perm = perm.substring(0, perm.length() - value.length() - 1);
boolean result = false;
if (numeric >= 0) {
int checkRange = PlotSquared.get().getPlatform().equalsIgnoreCase("bukkit") ?
numeric :
Settings.Limit.MAX_PLOTS;
result = player.hasPermissionRange(perm, checkRange) >= numeric;
}
if (!result) {
player.sendMessage(
TranslatableCaption.of("permission.no_permission"),
TagResolver.resolver(
"node",
Tag.inserting(Component.text(perm + "." + numeric))
)
);
}
return result;
} catch (NumberFormatException ignore) {
}
} else if (flag instanceof final ListFlag<?, ?> listFlag) {
try {
PlotFlag<? extends List<?>, ?> parsedFlag = listFlag.parse(value);
for (final Object entry : parsedFlag.getValue()) {
final String permission = Permission.PERMISSION_SET_FLAG_KEY_VALUE.format(
key.toLowerCase(),
entry.toString().toLowerCase()
);
final boolean result = player.hasPermission(permission);
if (!result) {
player.sendMessage(
TranslatableCaption.of("permission.no_permission"),
TagResolver.resolver("node", Tag.inserting(Component.text(permission)))
);
return false;
}
}
} catch (final FlagParseException e) {
player.sendMessage(
TranslatableCaption.of("flag.flag_parse_error"),
TagResolver.builder()
.tag("flag_name", Tag.inserting(Component.text(flag.getName())))
.tag("flag_value", Tag.inserting(Component.text(e.getValue())))
.tag("error", Tag.inserting(e.getErrorMessage().toComponent(player)))
.build()
);
return false;
} catch (final Exception e) {
return false;
}
return true;
}
boolean result;
String basePerm = Permission.PERMISSION_SET_FLAG_KEY.format(key.toLowerCase());
if (flag.isValuedPermission()) {
result = player.hasKeyedPermission(basePerm, value);
} else {
result = player.hasPermission(basePerm);
perm = basePerm;
}
if (!result) {
player.sendMessage(
TranslatableCaption.of("permission.no_permission"),
TagResolver.resolver("node", Tag.inserting(Component.text(perm)))
);
}
return result;
}
@Override
public final @NonNull CommandCategory category() {
return CommandCategory.SETTINGS;
}
@Override
public @NonNull List<@NonNull CommandRequirement> requirements() {
return List.of(CommonCommandRequirement.IS_OWNER.withPermissionOverride(Permission.PERMISSION_SET_FLAG_OTHER));
}
@Override
protected final Command.@NonNull Builder<PlotPlayer<?>> prepare(final Command.@NonNull Builder<PlotPlayer<?>> builder) {
return builder.literal("flag");
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.commands.command.setting.flag;
import com.plotsquared.core.commands.parser.PlotFlagParser;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.flag.PlotFlag;
import io.leangen.geantyref.TypeToken;
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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import static com.plotsquared.core.commands.parser.PlotFlagParser.plotFlagParser;
public final class FlagInfoCommand extends FlagCommandBean {
private static final CloudKey<PlotFlag<?, ?>> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken<PlotFlag<?, ?>>() {});
@Override
protected Command.@NonNull Builder<PlotPlayer<?>> configurePlotCommand(final Command.@NonNull Builder<PlotPlayer<?>> builder) {
return builder.literal("info")
.required(COMPONENT_FLAG, plotFlagParser(PlotFlagParser.FlagSource.GLOBAL));
}
@Override
public void execute(final @NonNull CommandContext<PlotPlayer<?>> commandContext) {
final PlotFlag<?, ?> plotFlag = commandContext.get(COMPONENT_FLAG);
final PlotPlayer<?> player = commandContext.sender();
player.sendMessage(TranslatableCaption.of("flag.flag_info_header"));
// Flag name
player.sendMessage(
TranslatableCaption.of("flag.flag_info_name"),
TagResolver.resolver("flag", Tag.inserting(Component.text(plotFlag.getName())))
);
// Flag category
player.sendMessage(
TranslatableCaption.of("flag.flag_info_category"),
TagResolver.resolver(
"value",
Tag.inserting(plotFlag.getFlagCategory().toComponent(player))
)
);
// Flag description
// TODO maybe merge and \n instead?
player.sendMessage(TranslatableCaption.of("flag.flag_info_description"));
player.sendMessage(plotFlag.getFlagDescription());
// Flag example
player.sendMessage(
TranslatableCaption.of("flag.flag_info_example"),
TagResolver.builder()
.tag("command", Tag.preProcessParsed("/plot flag set"))
.tag("flag", Tag.preProcessParsed(plotFlag.getName()))
.tag("value", Tag.preProcessParsed(plotFlag.getExample()))
.build()
);
// Default value
final String defaultValue = player.getLocation().getPlotArea().getFlagContainer()
.getFlagErased(plotFlag.getClass()).toString();
player.sendMessage(
TranslatableCaption.of("flag.flag_info_default_value"),
TagResolver.resolver("value", Tag.inserting(Component.text(defaultValue)))
);
// Footer. Done this way to prevent the duplicate-message-thingy from catching it
player.sendMessage(TranslatableCaption.of("flag.flag_info_footer"));
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.commands.command.setting.flag;
import com.plotsquared.core.configuration.caption.StaticCaption;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.flag.InternalFlag;
import com.plotsquared.core.plot.flag.PlotFlag;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.Style;
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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public final class FlagListCommand extends FlagCommandBean {
private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build();
@Override
protected Command.@NonNull Builder<PlotPlayer<?>> configurePlotCommand(
final Command.@NonNull Builder<PlotPlayer<?>> builder
) {
return builder.literal("list");
}
@Override
public void execute(final @NonNull CommandContext<PlotPlayer<?>> commandContext) {
final PlotPlayer<?> player = commandContext.sender();
final Map<Component, ArrayList<String>> flags = new HashMap<>();
for (PlotFlag<?, ?> plotFlag : GlobalFlagContainer.getInstance().getRecognizedPlotFlags()) {
if (plotFlag instanceof InternalFlag) {
continue;
}
final Component category = plotFlag.getFlagCategory().toComponent(player);
final Collection<String> flagList = flags.computeIfAbsent(category, k -> new ArrayList<>());
flagList.add(plotFlag.getName());
}
for (final Map.Entry<Component, ArrayList<String>> entry : flags.entrySet()) {
Collections.sort(entry.getValue());
Component category =
MINI_MESSAGE.deserialize(
TranslatableCaption.of("flag.flag_list_categories").getComponent(player),
TagResolver.resolver("category", Tag.inserting(entry.getKey().style(Style.empty())))
);
TextComponent.Builder builder = Component.text().append(category);
final Iterator<String> flagIterator = entry.getValue().iterator();
while (flagIterator.hasNext()) {
final String flag = flagIterator.next();
builder.append(MINI_MESSAGE
.deserialize(
TranslatableCaption.of("flag.flag_list_flag").getComponent(player),
TagResolver.builder()
.tag("command", Tag.preProcessParsed("/plat flag info " + flag))
.tag("flag", Tag.inserting(Component.text(flag)))
.tag("suffix", Tag.inserting(Component.text(flagIterator.hasNext() ? ", " : "")))
.build()
));
}
player.sendMessage(StaticCaption.of(MINI_MESSAGE.serialize(builder.build())));
}
}
}

View File

@ -0,0 +1,171 @@
/*
* 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.commands.command.setting.flag;
import com.google.inject.Inject;
import com.plotsquared.core.commands.parser.PlotFlagParser;
import com.plotsquared.core.commands.suggestions.FlagValueSuggestionProvider;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.events.PlotFlagAddEvent;
import com.plotsquared.core.events.PlotFlagRemoveEvent;
import com.plotsquared.core.events.Result;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.FlagParseException;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.plot.flag.types.ListFlag;
import com.plotsquared.core.util.EventDispatcher;
import io.leangen.geantyref.TypeToken;
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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static com.plotsquared.core.commands.parser.PlotFlagParser.plotFlagParser;
import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser;
public final class FlagRemoveCommand extends FlagCommandBean {
private static final CloudKey<PlotFlag<?, ?>> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken<PlotFlag<?, ?>>() {});
private static final CloudKey<String> COMPONENT_VALUE = CloudKey.of("value", String.class);
private final EventDispatcher eventDispatcher;
@Inject
public FlagRemoveCommand(final @NonNull EventDispatcher eventDispatcher) {
this.eventDispatcher = eventDispatcher;
}
@Override
protected Command.@NonNull Builder<PlotPlayer<?>> configurePlotCommand(
final Command.@NonNull Builder<PlotPlayer<?>> builder
) {
return builder.literal("remove")
.required(COMPONENT_FLAG, plotFlagParser(PlotFlagParser.FlagSource.PLOT))
.optional(COMPONENT_VALUE, greedyStringParser(), new FlagValueSuggestionProvider(COMPONENT_FLAG));
}
@Override
public void execute(final @NonNull CommandContext<PlotPlayer<?>> commandContext) {
final PlotPlayer<?> player = commandContext.sender();
final Plot plot = commandContext.inject(Plot.class).orElseThrow();
final PlotFlag<?, ?> flag = commandContext.get(COMPONENT_FLAG);
final String flagValue = commandContext.getOrDefault(COMPONENT_VALUE, null);
final PlotFlagRemoveEvent event = this.eventDispatcher.callFlagRemove(flag, plot);
if (event.getEventResult() == Result.DENY) {
player.sendMessage(
TranslatableCaption.of("events.event_denied"),
TagResolver.resolver("value", Tag.inserting(Component.text("Flag set")))
);
return;
}
final String flagKey = flag.getName().toLowerCase(Locale.ENGLISH);
if (event.getEventResult() != Result.FORCE
&& !player.hasPermission(Permission.PERMISSION_SET_FLAG_KEY.format(flagKey))) {
if (flagValue == null) {
player.sendMessage(
TranslatableCaption.of("permission.no_permission"),
TagResolver.resolver(
"node",
Tag.inserting(Component.text(Permission.PERMISSION_SET_FLAG_KEY.format(flagKey)))
)
);
return;
}
}
if (flagValue != null && flag instanceof ListFlag<?,?> listFlag) {
final List<?> list = new ArrayList<>(plot.getFlag(listFlag));
final PlotFlag parsedFlag;
try {
parsedFlag = listFlag.parse(flagValue);
} catch (final FlagParseException e) {
player.sendMessage(
TranslatableCaption.of("flag.flag_parse_error"),
TagResolver.builder()
.tag("flag_name", Tag.inserting(Component.text(flag.getName())))
.tag("flag_value", Tag.inserting(Component.text(e.getValue())))
.tag("error", Tag.inserting(e.getErrorMessage().toComponent(player)))
.build()
);
return;
}
if (((List<?>) parsedFlag.getValue()).isEmpty()) {
player.sendMessage(TranslatableCaption.of("flag.flag_not_removed"));
return;
}
if (list.removeAll((List) parsedFlag.getValue())) {
if (list.isEmpty()) {
if (plot.removeFlag(flag)) {
player.sendMessage(
TranslatableCaption.of("flag.flag_removed"),
TagResolver.builder()
.tag("flag", Tag.inserting(Component.text(flagKey)))
.tag("value", Tag.inserting(Component.text(flag.toString())))
.build()
);
return;
} else {
player.sendMessage(TranslatableCaption.of("flag.flag_not_removed"));
return;
}
} else {
PlotFlag<?, ?> plotFlag = parsedFlag.createFlagInstance(list);
PlotFlagAddEvent addEvent = eventDispatcher.callFlagAdd(plotFlag, plot);
if (addEvent.getEventResult() == Result.DENY) {
player.sendMessage(
TranslatableCaption.of("events.event_denied"),
TagResolver.resolver(
"value",
Tag.inserting(Component.text("Re-addition of " + plotFlag.getName()))
)
);
return;
}
if (plot.setFlag(addEvent.getFlag())) {
player.sendMessage(TranslatableCaption.of("flag.flag_partially_removed"));
return;
} else {
player.sendMessage(TranslatableCaption.of("flag.flag_not_removed"));
return;
}
}
}
} else if (!plot.removeFlag(flag)) {
player.sendMessage(TranslatableCaption.of("flag.flag_not_removed"));
return;
}
player.sendMessage(
TranslatableCaption.of("flag.flag_removed"),
TagResolver.builder()
.tag("flag", Tag.inserting(Component.text(flagKey)))
.tag("value", Tag.inserting(Component.text(flag.toString())))
.build()
);
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.commands.command.setting.flag;
import com.google.inject.Inject;
import com.plotsquared.core.commands.parser.PlotFlagParser;
import com.plotsquared.core.commands.suggestions.FlagValueSuggestionProvider;
import com.plotsquared.core.configuration.caption.CaptionUtility;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.events.PlotFlagAddEvent;
import com.plotsquared.core.events.Result;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.FlagParseException;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.util.EventDispatcher;
import io.leangen.geantyref.TypeToken;
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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.key.CloudKey;
import static com.plotsquared.core.commands.parser.PlotFlagParser.plotFlagParser;
import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser;
public final class FlagSetCommand extends FlagCommandBean {
private static final CloudKey<PlotFlag<?, ?>> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken<PlotFlag<?, ?>>() {});
private static final CloudKey<String> COMPONENT_VALUE = CloudKey.of("value", String.class);
private final EventDispatcher eventDispatcher;
@Inject
public FlagSetCommand(final @NonNull EventDispatcher eventDispatcher) {
this.eventDispatcher = eventDispatcher;
}
@Override
protected Command.@NonNull Builder<PlotPlayer<?>> configurePlotCommand(
final Command.@NonNull Builder<PlotPlayer<?>> builder
) {
return builder.literal("set")
.required(COMPONENT_FLAG, plotFlagParser(PlotFlagParser.FlagSource.GLOBAL))
.required(COMPONENT_VALUE, greedyStringParser(), new FlagValueSuggestionProvider(COMPONENT_FLAG));
}
@Override
public void execute(final @NonNull CommandContext<PlotPlayer<?>> commandContext) {
final PlotPlayer<?> player = commandContext.sender();
final Plot plot = commandContext.inject(Plot.class).orElseThrow();
final PlotFlag<?, ?> flag = commandContext.get(COMPONENT_FLAG);
final String flagValue = commandContext.get(COMPONENT_VALUE);
final PlotFlagAddEvent event = this.eventDispatcher.callFlagAdd(flag, plot);
if (event.getEventResult() == Result.DENY) {
player.sendMessage(
TranslatableCaption.of("events.event_denied"),
TagResolver.resolver("value", Tag.inserting(Component.text("Flag set")))
);
return;
}
if (event.getEventResult() != Result.FORCE && !checkPermValue(player, flag, flag.getName(), flagValue)) {
return;
}
final String sanitizedValue = CaptionUtility.stripClickEvents(flag, flagValue);
final PlotFlag<?, ?> parsedFlag;
try {
parsedFlag = flag.parse(flagValue);
} catch (final FlagParseException e) {
player.sendMessage(
TranslatableCaption.of("flag.flag_parse_error"),
TagResolver.builder()
.tag("flag_name", Tag.inserting(Component.text(flag.getName())))
.tag("flag_value", Tag.inserting(Component.text(e.getValue())))
.tag("error", Tag.inserting(e.getErrorMessage().toComponent(player)))
.build()
);
return;
}
plot.setFlag(parsedFlag);
player.sendMessage(
TranslatableCaption.of("flag.flag_added"),
TagResolver.builder()
.tag("flag", Tag.inserting(Component.text(flag.getName())))
.tag("value", Tag.inserting(Component.text(parsedFlag.toString())))
.build()
);
}
}

View File

@ -16,28 +16,27 @@
* 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.plot.flag.implementations;
package com.plotsquared.core.commands.injection;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.plot.flag.types.BooleanFlag;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.injection.ParameterInjector;
import org.incendo.cloud.util.annotation.AnnotationAccessor;
/**
* @since 7.3.7
* {@link ParameterInjector} that returns the current plot of the player.
*/
public class TileDropFlag extends BooleanFlag<TileDropFlag> {
public static final TileDropFlag TILE_DROP_TRUE = new TileDropFlag(true);
public static final TileDropFlag TILE_DROP_FALSE = new TileDropFlag(false);
private TileDropFlag(boolean value) {
super(value, TranslatableCaption.of("flags.flag_description_tile_drop"));
}
public final class PlotInjector implements ParameterInjector<PlotPlayer<?>, Plot> {
@Override
protected TileDropFlag flagOf(@NonNull Boolean value) {
return value ? TILE_DROP_TRUE : TILE_DROP_FALSE;
public @Nullable Plot create(
final @NonNull CommandContext<PlotPlayer<?>> context,
final @NonNull AnnotationAccessor annotationAccessor
) {
// TODO: Allow for overriding for console.
return context.sender().getCurrentPlot();
}
}

View File

@ -0,0 +1,158 @@
/*
* 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.commands.parser;
import com.plotsquared.core.configuration.caption.LocaleHolder;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.FlagContainer;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.flag.InternalFlag;
import com.plotsquared.core.plot.flag.PlotFlag;
import io.leangen.geantyref.TypeToken;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.util.ComponentMessageThrowable;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.exception.parsing.ParserException;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.parser.ArgumentParser;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
import org.incendo.cloud.suggestion.Suggestion;
import java.util.Collection;
import java.util.function.Function;
/**
* Parser that parses and suggests {@link PlotFlag plot flags}.
*/
public final class PlotFlagParser implements ArgumentParser<PlotPlayer<?>, PlotFlag<?, ?>>,
BlockingSuggestionProvider<PlotPlayer<?>> {
/**
* Returns a new parser that parses {@link PlotFlag plot flags}.
*
* @param source the source of available flag values
* @return the parser
*/
public static @NonNull ParserDescriptor<PlotPlayer<?>, PlotFlag<?, ?>> plotFlagParser(final @NonNull FlagSource source) {
return ParserDescriptor.of(new PlotFlagParser(source), new TypeToken<PlotFlag<?, ?>>() {
});
}
private final FlagSource flagSource;
private PlotFlagParser(final @NonNull FlagSource flagSource) {
this.flagSource = flagSource;
}
@Override
public @NonNull ArgumentParseResult<@NonNull PlotFlag<?, ?>> parse(
final @NonNull CommandContext<@NonNull PlotPlayer<?>> commandContext,
final @NonNull CommandInput commandInput
) {
final String flagName = commandInput.readString();
final PlotFlag<?, ?> flag = GlobalFlagContainer.getInstance().getFlagFromString(flagName);
if (flag == null) {
return ArgumentParseResult.failure(new PlotFlagParseException(commandContext));
}
return ArgumentParseResult.success(flag);
}
@Override
public @NonNull Iterable<@NonNull Suggestion> suggestions(
final @NonNull CommandContext<PlotPlayer<?>> context,
final @NonNull CommandInput input
) {
return this.flagSource.flags(context.sender())
.stream()
.filter(flag -> (!(flag instanceof InternalFlag)))
.map(PlotFlag::getName)
.map(Suggestion::simple)
.toList();
}
public enum FlagSource {
/**
* All recognized flags.
*/
GLOBAL(player -> GlobalFlagContainer.getInstance(), false),
/**
* All flags that have been configured in the current plot.
*/
PLOT(player -> {
final Plot plot = player.getCurrentPlot();
if (plot == null) {
return GlobalFlagContainer.getInstance();
}
return plot.getFlagContainer();
}, true);
private final Function<PlotPlayer<?>, FlagContainer> containerFunction;
private final boolean storedOnly;
FlagSource(final @NonNull Function<PlotPlayer<?>, FlagContainer> containerFunction, final boolean storedOnly) {
this.containerFunction = containerFunction;
this.storedOnly = storedOnly;
}
/**
* Returns the flag container.
*
* @param player the player to get the container for
* @return the container
*/
public @NonNull FlagContainer flagContainer(final @NonNull PlotPlayer<?> player) {
return this.containerFunction.apply(player);
}
/**
* Returns the flags from this source.
*
* @param player the player to get the flags for
* @return the flags
*/
public @NonNull Collection<@NonNull PlotFlag<?, ?>> flags(final @NonNull PlotPlayer<?> player) {
final FlagContainer container = this.flagContainer(player);
if (this.storedOnly) {
return container.getFlagMap().values();
}
return container.getRecognizedPlotFlags();
}
}
/**
* Exception thrown when an invalid flag name is supplied.
*/
public static final class PlotFlagParseException extends ParserException implements ComponentMessageThrowable {
private PlotFlagParseException(final @NonNull CommandContext<?> context) {
super(PlotFlagParser.class, context, TranslatableCaption.of("flag.not_valid_flag"));
}
@Override
public @NonNull Component componentMessage() {
// TODO(City): This sucks...
return ((TranslatableCaption) this.errorCaption()).toComponent(LocaleHolder.console());
}
}
}

View File

@ -0,0 +1,86 @@
/*
* 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.commands.suggestions;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.plot.flag.types.ListFlag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Suggestion provider that provides context-aware {@link PlotFlag plot flag} value suggestions using
* {@link PlotFlag#getTabCompletions()}.
*/
public final class FlagValueSuggestionProvider implements BlockingSuggestionProvider.Strings<PlotPlayer<?>> {
private final CloudKey<PlotFlag<?, ?>> flagKey;
/**
* Creates a new suggestion provider.
*
* @param flagKey the key of the argument that contains the flag to provide value suggestions for
*/
public FlagValueSuggestionProvider(final @NonNull CloudKey<PlotFlag<?, ?>> flagKey) {
this.flagKey = Objects.requireNonNull(flagKey, "flagKey");
}
@Override
public @NonNull Iterable<@NonNull String> stringSuggestions(
@NonNull final CommandContext<PlotPlayer<?>> context,
@NonNull final CommandInput input
) {
final PlotFlag<?, ?> plotFlag = context.getOrDefault(this.flagKey, null);
if (plotFlag == null) {
return List.of();
}
final Collection<String> completions = plotFlag.getTabCompletions();
if (plotFlag instanceof ListFlag<?,?> && input.peekString().contains(",")) {
final String[] split = input.peekString().split(",");
final List<String> existingValues = new ArrayList<>(Arrays.asList(split));
final String completingValue;
if (!input.peekString().endsWith(",")) {
// In this case we want to complete the value we're currently typing.
completingValue = split[split.length - 1];
existingValues.remove(existingValues.size() - 1);
} else {
completingValue = null;
}
final String prefix = existingValues.stream().collect(Collectors.joining(",", "", ","));
return completions.stream()
.filter(value -> !existingValues.contains(value))
.filter(value -> completingValue == null || value.startsWith(completingValue))
.map(value -> prefix + value)
.toList();
}
return completions;
}
}

View File

@ -26,7 +26,6 @@ import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.PrintWriter;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -373,7 +372,6 @@ public class Config {
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@Documented
public @interface Comment {
String[] value();

View File

@ -43,11 +43,6 @@ public class Settings extends Config {
"Leave it off if you don't need it, it can spam your console."})
public static boolean DEBUG = true;
@Comment({"The activity of high-frequency event listener can be deactivated here to improve the server performance. ",
"Affected settings: 'redstone' settings here below. Affected flags: 'disable-physics', 'redstone'. ",
"Only deactivate this setting if you do not need any of the mentioned settings or flags."})
public static boolean HIGH_FREQUENCY_LISTENER = true;
@Create // This value will be generated automatically
public static ConfigBlock<Auto_Clear> AUTO_CLEAR = null;
// A ConfigBlock is a section that can have multiple instances e.g. multiple expiry tasks
@ -582,8 +577,6 @@ public class Settings extends Config {
public static boolean PER_WORLD_VISIT = false;
@Comment("Search merged plots for having multiple owners when using the visit command")
public static boolean VISIT_MERGED_OWNERS = true;
@Comment("Allows to teleport based on block size instead to spawn on the highest block at the home command")
public static boolean SIZED_BASED = true;
}
@ -653,8 +646,6 @@ public class Settings extends Config {
public static boolean PAPER_LISTENERS = true;
@Comment("Prevent entities from leaving plots")
public static boolean ENTITY_PATHING = true;
@Comment("Prevent entities from leaving plots, even by pushing or pulling")
public static boolean ENTITY_MOVEMENT = false;
@Comment(
"Cancel entity spawns when the chunk is loaded if the PlotArea's mob spawning is off")
public static boolean CANCEL_CHUNK_SPAWN = true;
@ -732,12 +723,6 @@ public class Settings extends Config {
}
@Comment("Settings related to flags")
public static final class Flags {
@Comment("If \"instabreak\" should consider the used tool.")
public static boolean INSTABREAK_CONSIDER_TOOL = false;
}
@Comment({"Enable or disable parts of the plugin",
"Note: A cache will use some memory if enabled"})

View File

@ -46,7 +46,7 @@ public class Storage extends Config {
public static String PASSWORD = "password";
public static String DATABASE = "plot_db";
@Comment("Set additional properties: https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html")
@Comment("Set additional properties: https://goo.gl/wngtN8")
public static List<String>
PROPERTIES = new ArrayList<>(Collections.singletonList("useSSL=false"));

View File

@ -25,6 +25,7 @@ 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.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.caption.Caption;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
@ -33,7 +34,7 @@ import java.util.regex.Pattern;
/**
* Caption that is user modifiable
*/
public final class TranslatableCaption implements NamespacedCaption {
public final class TranslatableCaption implements NamespacedCaption, Caption {
/**
* Default caption namespace
@ -72,6 +73,11 @@ public final class TranslatableCaption implements NamespacedCaption {
);
}
@Override
public @NonNull String key() {
return this.getKey();
}
/**
* Get a new {@link TranslatableCaption} instance
*

View File

@ -2401,8 +2401,7 @@ public class SQLManager implements AbstractDB {
addPlotTask(plot, new UniqueStatement("setPosition") {
@Override
public void set(PreparedStatement statement) throws SQLException {
// Please see the table creation statement. There is the default value of "default"
statement.setString(1, position == null ? "DEFAULT" : position);
statement.setString(1, position == null ? "" : position);
statement.setInt(2, getId(plot));
}

View File

@ -18,34 +18,17 @@
*/
package com.plotsquared.core.events;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* PlotSquared event with {@link Result} to cancel, force, or allow.
*/
public interface CancellablePlotEvent {
/**
* The currently set {@link Result} for this event (as set by potential previous event listeners).
*
* @return the current result.
*/
@Nullable Result getEventResult();
Result getEventResult();
/**
* Set the {@link Result} for this event.
*
* @param eventResult the new result.
*/
void setEventResult(@Nullable Result eventResult);
void setEventResult(Result eventResult);
/**
* @deprecated No usage and not null-safe
*/
@Deprecated(since = "7.3.2")
default int getEventResultRaw() {
return getEventResult() != null ? getEventResult().getValue() : -1;
return getEventResult().getValue();
}
}

View File

@ -1,88 +0,0 @@
/*
* 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.events;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Called when a user attempts to buy a plot.
* <p>
* Setting the {@link #setEventResult(Result) Result} to {@link Result#FORCE} ignores the price and players account balance and does not charge the
* player anything. {@link Result#DENY} blocks the purchase completely, {@link Result#ACCEPT} and {@code null} do not modify
* the behaviour.
* <p>
* Setting the {@link #setPrice(double) price} to {@code 0} makes the plot practically free.
*
* @since 7.3.2
*/
public class PlayerBuyPlotEvent extends PlotPlayerEvent implements CancellablePlotEvent {
private Result result;
private double price;
public PlayerBuyPlotEvent(final PlotPlayer<?> plotPlayer, final Plot plot, @NonNegative final double price) {
super(plotPlayer, plot);
this.price = price;
}
/**
* Sets the price required to buy the plot.
*
* @param price the new price.
* @since 7.3.2
*/
public void setPrice(@NonNegative final double price) {
//noinspection ConstantValue - the annotation does not ensure a non-negative runtime value
if (price < 0) {
throw new IllegalArgumentException("price must be non-negative");
}
this.price = price;
}
/**
* Returns the currently set price required to buy the plot.
*
* @return the price.
* @since 7.3.2
*/
public @NonNegative double price() {
return price;
}
/**
* {@inheritDoc}
*/
@Override
public void setEventResult(@Nullable final Result eventResult) {
this.result = eventResult;
}
/**
* {@inheritDoc}
*/
@Override
public @Nullable Result getEventResult() {
return this.result;
}
}

View File

@ -24,7 +24,7 @@ import com.plotsquared.core.plot.Plot;
public class PlayerEnterPlotEvent extends PlotPlayerEvent {
/**
* PlayerEnterPlotEvent: Called when a player enters a plot
* Called when a player leaves a plot.
*
* @param player Player that entered the plot
* @param plot Plot that was entered

View File

@ -1,64 +0,0 @@
/*
* 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.events.post;
import com.plotsquared.core.events.PlotPlayerEvent;
import com.plotsquared.core.player.OfflinePlotPlayer;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import org.checkerframework.checker.index.qual.NonNegative;
/**
* Called after a player has successfully bought a plot.
*
* @since 7.3.2
*/
public class PostPlayerBuyPlotEvent extends PlotPlayerEvent {
private final OfflinePlotPlayer previousOwner;
private final double price;
public PostPlayerBuyPlotEvent(
final PlotPlayer<?> plotPlayer, final OfflinePlotPlayer previousOwner, final Plot plot,
@NonNegative final double price
) {
super(plotPlayer, plot);
this.previousOwner = previousOwner;
this.price = price;
}
/**
* The previous owner of the bought plot.
*
* @return the previous owner.
*/
public OfflinePlotPlayer previousOwner() {
return previousOwner;
}
/**
* Returns the price after potential modifications by {@link com.plotsquared.core.events.PlayerBuyPlotEvent}.
*
* @return the price the player had to pay to buy the plot.
*/
public double price() {
return price;
}
}

View File

@ -143,7 +143,7 @@ public class ClassicPlotManager extends SquarePlotManager {
classicPlotWorld,
plot.getRegions(),
blocks,
classicPlotWorld.getMinComponentHeight(),
classicPlotWorld.getMinBuildHeight(),
classicPlotWorld.getMaxBuildHeight() - 1,
actor,
queue
@ -204,7 +204,7 @@ public class ClassicPlotManager extends SquarePlotManager {
classicPlotWorld,
plot.getRegions(),
blocks,
classicPlotWorld.getMinComponentHeight(),
classicPlotWorld.getMinBuildHeight(),
classicPlotWorld.PLOT_HEIGHT - 1,
actor,
queue
@ -379,7 +379,7 @@ public class ClassicPlotManager extends SquarePlotManager {
}
}
int yStart = classicPlotWorld.getMinComponentHeight();
int yStart = classicPlotWorld.getMinBuildHeight() + (classicPlotWorld.PLOT_BEDROCK ? 1 : 0);
if (!plot.isMerged(Direction.NORTH)) {
int z = bot.getZ();
for (int x = bot.getX(); x < top.getX(); x++) {

View File

@ -52,7 +52,6 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld {
public BlockBucket ROAD_BLOCK = new BlockBucket(BlockTypes.QUARTZ_BLOCK);
public boolean PLOT_BEDROCK = true;
public boolean PLACE_TOP_BLOCK = true;
public boolean COMPONENT_BELOW_BEDROCK = false;
public ClassicPlotWorld(
final @NonNull String worldName,
@ -130,9 +129,6 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld {
),
new ConfigurationNode("plot.bedrock", this.PLOT_BEDROCK, TranslatableCaption.of("setup.bedrock_boolean"),
ConfigurationUtil.BOOLEAN
),
new ConfigurationNode("world.component_below_bedrock", this.COMPONENT_BELOW_BEDROCK, TranslatableCaption.of(
"setup.component_below_bedrock_boolean"), ConfigurationUtil.BOOLEAN
)};
}
@ -154,14 +150,6 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld {
this.PLACE_TOP_BLOCK = config.getBoolean("wall.place_top_block");
this.WALL_HEIGHT = Math.min(getMaxGenHeight() - (PLACE_TOP_BLOCK ? 1 : 0), config.getInt("wall.height"));
this.CLAIMED_WALL_BLOCK = createCheckedBlockBucket(config.getString("wall.block_claimed"), CLAIMED_WALL_BLOCK);
this.COMPONENT_BELOW_BEDROCK = config.getBoolean("world.component_below_bedrock");
}
@Override
public int getMinComponentHeight() {
return COMPONENT_BELOW_BEDROCK && getMinGenHeight() >= getMinBuildHeight()
? getMinGenHeight() + (PLOT_BEDROCK ? 1 : 0)
: getMinBuildHeight();
}
int schematicStartHeight() {

View File

@ -432,7 +432,6 @@ public class HybridUtils {
if (!UPDATE) {
Iterator<BlockVector2> iter = chunks.iterator();
QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName()));
queue.setShouldGen(false);
while (iter.hasNext()) {
BlockVector2 chunk = iter.next();
iter.remove();
@ -475,7 +474,6 @@ public class HybridUtils {
Iterator<BlockVector2> iterator = chunks.iterator();
if (chunks.size() >= 32) {
QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName()));
queue.setShouldGen(false);
for (int i = 0; i < 32; i++) {
final BlockVector2 chunk = iterator.next();
iterator.remove();
@ -489,7 +487,6 @@ public class HybridUtils {
return null;
}
QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName()));
queue.setShouldGen(false);
while (!chunks.isEmpty()) {
final BlockVector2 chunk = iterator.next();
iterator.remove();
@ -505,6 +502,7 @@ public class HybridUtils {
return;
}
} catch (Exception e) {
e.printStackTrace();
Iterator<BlockVector2> iterator = HybridUtils.regions.iterator();
BlockVector2 loc = iterator.next();
iterator.remove();
@ -512,8 +510,7 @@ public class HybridUtils {
"Error! Could not update '{}/region/r.{}.{}.mca' (Corrupt chunk?)",
area.getWorldHash(),
loc.getX(),
loc.getZ(),
e
loc.getZ()
);
}
TaskManager.runTaskLater(task, TaskTime.seconds(1L));
@ -561,7 +558,7 @@ public class HybridUtils {
try {
plotworld.setupSchematics();
} catch (SchematicHandler.UnsupportedFormatException e) {
LOGGER.error(e);
e.printStackTrace();
}
});
});

View File

@ -40,8 +40,7 @@ public interface ChunkCoordinatorFactory {
final @NonNull Consumer<Throwable> throwableConsumer,
@Assisted("unloadAfter") final boolean unloadAfter,
final @NonNull Collection<ProgressSubscriber> progressSubscribers,
@Assisted("forceSync") final boolean forceSync,
@Assisted("shouldGen") final boolean shouldGen
@Assisted("forceSync") final boolean forceSync
);
}

View File

@ -0,0 +1,46 @@
/*
* 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.inject.modules;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import com.google.inject.multibindings.Multibinder;
import com.plotsquared.core.commands.PlotSquaredCommandBean;
import com.plotsquared.core.commands.command.setting.flag.FlagAddCommand;
import com.plotsquared.core.commands.command.setting.flag.FlagInfoCommand;
import com.plotsquared.core.commands.command.setting.flag.FlagListCommand;
import com.plotsquared.core.commands.command.setting.flag.FlagRemoveCommand;
import com.plotsquared.core.commands.command.setting.flag.FlagSetCommand;
public final class CommandModule extends AbstractModule {
@Override
protected void configure() {
final Multibinder<PlotSquaredCommandBean> commands = Multibinder.newSetBinder(
this.binder(),
PlotSquaredCommandBean.class
);
commands.addBinding().to(FlagAddCommand.class).in(Scopes.SINGLETON);
commands.addBinding().to(FlagInfoCommand.class).in(Scopes.SINGLETON);
commands.addBinding().to(FlagListCommand.class).in(Scopes.SINGLETON);
commands.addBinding().to(FlagRemoveCommand.class).in(Scopes.SINGLETON);
commands.addBinding().to(FlagSetCommand.class).in(Scopes.SINGLETON);
}
}

View File

@ -18,7 +18,6 @@
*/
package com.plotsquared.core.inject.modules;
import cloud.commandframework.services.ServicePipeline;
import com.google.inject.AbstractModule;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.file.YamlConfiguration;
@ -31,6 +30,7 @@ import com.plotsquared.core.listener.PlotListener;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.uuid.UUIDPipeline;
import com.sk89q.worldedit.WorldEdit;
import org.incendo.cloud.services.ServicePipeline;
import java.io.File;

View File

@ -106,10 +106,6 @@ public class PlotListener {
iterator.remove();
continue;
}
// Don't attempt to heal dead players - they will get stuck in the abyss (#4406)
if (PlotSquared.platform().worldUtil().getHealth(player) <= 0) {
continue;
}
double level = PlotSquared.platform().worldUtil().getHealth(player);
if (level != value.max) {
PlotSquared.platform().worldUtil().setHealth(player, Math.min(level + value.amount, value.max));

View File

@ -444,7 +444,7 @@ public abstract class PlotPlayer<P> implements CommandCaller, OfflinePlotPlayer,
/**
* Get this player's UUID.
* <p>=== !IMPORTANT ===</p>
* === !IMPORTANT ===<br>
* 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)
*

View File

@ -643,22 +643,35 @@ public class Plot {
}
/**
* Gets an immutable set of owner UUIDs for a plot (supports multi-owner mega-plots).
* Gets a immutable set of owner UUIDs for a plot (supports multi-owner mega-plots).
* <p>
* This method cannot be used to add or remove owners from a plot.
* </p>
*
* @return Immutable set of plot owners
* @return Immutable view of plot owners
*/
public @NonNull Set<UUID> getOwners() {
ImmutableSet.Builder<UUID> owners = ImmutableSet.builder();
for (Plot plot : getConnectedPlots()) {
UUID owner = plot.getOwner();
if (owner != null) {
owners.add(owner);
}
if (this.getOwner() == null) {
return ImmutableSet.of();
}
return owners.build();
if (isMerged()) {
Set<Plot> plots = getConnectedPlots();
Plot[] array = plots.toArray(new Plot[0]);
ImmutableSet.Builder<UUID> owners = ImmutableSet.builder();
UUID last = this.getOwner();
owners.add(this.getOwner());
for (final Plot current : array) {
if (current.getOwner() == null) {
continue;
}
if (last == null || current.getOwner().getMostSignificantBits() != last.getMostSignificantBits()) {
owners.add(current.getOwner());
last = current.getOwner();
}
}
return owners.build();
}
return ImmutableSet.of(this.getOwner());
}
/**
@ -1407,9 +1420,6 @@ public class Plot {
);
}
Location location = toHomeLocation(bottom, home);
if (Settings.Teleport.SIZED_BASED && this.worldUtil.isSmallBlock(location) && this.worldUtil.isSmallBlock(location.add(0,1,0))) {
return location;
}
if (!this.worldUtil.getBlockSynchronous(location).getBlockType().getMaterial().isAir()) {
location = location.withY(
Math.max(1 + this.worldUtil.getHighestBlockSynchronous(
@ -1443,21 +1453,15 @@ public class Plot {
}
Location bottom = this.getBottomAbs();
Location location = toHomeLocation(bottom, home);
if (Settings.Teleport.SIZED_BASED && this.worldUtil.isSmallBlock(location) && this.worldUtil.isSmallBlock(location.add(0,1,0))) {
result.accept(location);
} else {
this.worldUtil.getBlock(location, block -> {
if (!block.getBlockType().getMaterial().isAir()) {
this.worldUtil.getHighestBlock(this.getWorldName(), location.getX(), location.getZ(),
y -> result.accept(location.withY(Math.max(1 + y, bottom.getY())))
);
} else {
result.accept(location);
}
});
}
this.worldUtil.getBlock(location, block -> {
if (!block.getBlockType().getMaterial().isAir()) {
this.worldUtil.getHighestBlock(this.getWorldName(), location.getX(), location.getZ(),
y -> result.accept(location.withY(Math.max(1 + y, bottom.getY())))
);
} else {
result.accept(location);
}
});
}
}
@ -1479,7 +1483,7 @@ public class Plot {
*/
public void setHome(BlockLoc location) {
Plot plot = this.getBasePlot(false);
if (location != null && (BlockLoc.ZERO.equals(location) || BlockLoc.MINY.equals(location))) {
if (BlockLoc.ZERO.equals(location) || BlockLoc.MINY.equals(location)) {
return;
}
plot.getSettings().setPosition(location);
@ -1717,7 +1721,6 @@ 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) {
@ -2192,9 +2195,6 @@ public class Plot {
* @return if the given player can claim the plot
*/
public boolean canClaim(@NonNull PlotPlayer<?> player) {
if (!WorldUtil.isValidLocation(getBottomAbs())) {
return false;
}
PlotCluster cluster = this.getCluster();
if (cluster != null) {
if (!cluster.isAdded(player.getUUID()) && !player.hasPermission("plots.admin.command.claim")) {
@ -2574,12 +2574,6 @@ public class Plot {
*/
public void teleportPlayer(final PlotPlayer<?> player, TeleportCause cause, Consumer<Boolean> resultConsumer) {
Plot plot = this.getBasePlot(false);
if ((getArea() == null || !(getArea() instanceof SinglePlotArea)) && !WorldUtil.isValidLocation(plot.getBottomAbs())) {
// prevent from teleporting into unsafe regions
player.sendMessage(TranslatableCaption.of("border.denied"));
resultConsumer.accept(false);
return;
}
PlayerTeleportToPlotEvent event = this.eventDispatcher.callTeleport(player, player.getLocation(), plot, cause);
if (event.getEventResult() == Result.DENY) {

View File

@ -679,8 +679,10 @@ public abstract class PlotArea implements ComponentLike {
TranslatableCaption.of("height.height_limit"),
TagResolver.builder()
.tag("minheight", Tag.inserting(Component.text(minBuildHeight)))
.tag("maxheight", Tag.inserting(Component.text(maxBuildHeight)))
.build()
.tag(
"maxheight",
Tag.inserting(Component.text(maxBuildHeight))
).build()
);
// Return true if "failed" as the method will always be inverted otherwise
return true;
@ -1450,24 +1452,6 @@ public abstract class PlotArea implements ComponentLike {
this.defaultHome = defaultHome;
}
/**
* Get the maximum height that changes to plot components (wall filling, air, all etc.) may operate to
*
* @since 7.3.4
*/
public int getMaxComponentHeight() {
return this.maxBuildHeight;
}
/**
* Get the minimum height that changes to plot components (wall filling, air, all etc.) may operate to
*
* @since 7.3.4
*/
public int getMinComponentHeight() {
return this.minBuildHeight;
}
/**
* Get the maximum height players may build in. Exclusive.
*/

View File

@ -48,7 +48,6 @@ import com.plotsquared.core.plot.flag.implementations.EntityChangeBlockFlag;
import com.plotsquared.core.plot.flag.implementations.ExplosionFlag;
import com.plotsquared.core.plot.flag.implementations.FarewellFlag;
import com.plotsquared.core.plot.flag.implementations.FeedFlag;
import com.plotsquared.core.plot.flag.implementations.FishingFlag;
import com.plotsquared.core.plot.flag.implementations.FlyFlag;
import com.plotsquared.core.plot.flag.implementations.ForcefieldFlag;
import com.plotsquared.core.plot.flag.implementations.GamemodeFlag;
@ -65,7 +64,6 @@ import com.plotsquared.core.plot.flag.implementations.HostileInteractFlag;
import com.plotsquared.core.plot.flag.implementations.IceFormFlag;
import com.plotsquared.core.plot.flag.implementations.IceMeltFlag;
import com.plotsquared.core.plot.flag.implementations.InstabreakFlag;
import com.plotsquared.core.plot.flag.implementations.InteractionInteractFlag;
import com.plotsquared.core.plot.flag.implementations.InvincibleFlag;
import com.plotsquared.core.plot.flag.implementations.ItemDropFlag;
import com.plotsquared.core.plot.flag.implementations.KeepFlag;
@ -93,7 +91,6 @@ import com.plotsquared.core.plot.flag.implementations.PreventCreativeCopyFlag;
import com.plotsquared.core.plot.flag.implementations.PriceFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectileChangeBlockFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag;
import com.plotsquared.core.plot.flag.implementations.WeavingDeathPlace;
import com.plotsquared.core.plot.flag.implementations.PveFlag;
import com.plotsquared.core.plot.flag.implementations.PvpFlag;
import com.plotsquared.core.plot.flag.implementations.RedstoneFlag;
@ -104,7 +101,6 @@ import com.plotsquared.core.plot.flag.implementations.SnowMeltFlag;
import com.plotsquared.core.plot.flag.implementations.SoilDryFlag;
import com.plotsquared.core.plot.flag.implementations.TamedAttackFlag;
import com.plotsquared.core.plot.flag.implementations.TamedInteractFlag;
import com.plotsquared.core.plot.flag.implementations.TileDropFlag;
import com.plotsquared.core.plot.flag.implementations.TimeFlag;
import com.plotsquared.core.plot.flag.implementations.TitlesFlag;
import com.plotsquared.core.plot.flag.implementations.UntrustedVisitFlag;
@ -162,7 +158,6 @@ public final class GlobalFlagContainer extends FlagContainer {
this.addFlag(EditSignFlag.EDIT_SIGN_FALSE);
this.addFlag(EntityChangeBlockFlag.ENTITY_CHANGE_BLOCK_FALSE);
this.addFlag(ExplosionFlag.EXPLOSION_FALSE);
this.addFlag(FishingFlag.FISHING_FALSE);
this.addFlag(ForcefieldFlag.FORCEFIELD_FALSE);
this.addFlag(GrassGrowFlag.GRASS_GROW_TRUE);
this.addFlag(HangingBreakFlag.HANGING_BREAK_FALSE);
@ -173,7 +168,6 @@ public final class GlobalFlagContainer extends FlagContainer {
this.addFlag(IceFormFlag.ICE_FORM_FALSE);
this.addFlag(IceMeltFlag.ICE_MELT_FALSE);
this.addFlag(InstabreakFlag.INSTABREAK_FALSE);
this.addFlag(InteractionInteractFlag.INTERACTION_INTERACT_FALSE);
this.addFlag(InvincibleFlag.INVINCIBLE_FALSE);
this.addFlag(ItemDropFlag.ITEM_DROP_TRUE);
this.addFlag(KeepInventoryFlag.KEEP_INVENTORY_FALSE);
@ -202,7 +196,6 @@ public final class GlobalFlagContainer extends FlagContainer {
this.addFlag(SoilDryFlag.SOIL_DRY_FALSE);
this.addFlag(TamedAttackFlag.TAMED_ATTACK_FALSE);
this.addFlag(TamedInteractFlag.TAMED_INTERACT_FALSE);
this.addFlag(TileDropFlag.TILE_DROP_TRUE);
this.addFlag(UntrustedVisitFlag.UNTRUSTED_VISIT_FLAG_TRUE);
this.addFlag(VehicleBreakFlag.VEHICLE_BREAK_FALSE);
this.addFlag(VehiclePlaceFlag.VEHICLE_PLACE_FALSE);
@ -210,7 +203,6 @@ public final class GlobalFlagContainer extends FlagContainer {
this.addFlag(VillagerInteractFlag.VILLAGER_INTERACT_FALSE);
this.addFlag(VineGrowFlag.VINE_GROW_TRUE);
this.addFlag(ProjectilesFlag.PROJECTILES_FALSE);
this.addFlag(WeavingDeathPlace.WEAVING_DEATH_PLACE_FALSE);
// Double flags
this.addFlag(PriceFlag.PRICE_NOT_BUYABLE);

View File

@ -1,39 +0,0 @@
/*
* 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.plot.flag.implementations;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.plot.flag.types.BooleanFlag;
import org.checkerframework.checker.nullness.qual.NonNull;
public class InteractionInteractFlag extends BooleanFlag<InteractionInteractFlag> {
public static final InteractionInteractFlag INTERACTION_INTERACT_TRUE = new InteractionInteractFlag(true);
public static final InteractionInteractFlag INTERACTION_INTERACT_FALSE = new InteractionInteractFlag(false);
private InteractionInteractFlag(boolean value) {
super(value, TranslatableCaption.of("flags.flag_description_interaction_interact"));
}
@Override
protected InteractionInteractFlag flagOf(@NonNull Boolean value) {
return value ? INTERACTION_INTERACT_TRUE : INTERACTION_INTERACT_FALSE;
}
}

View File

@ -1,39 +0,0 @@
/*
* 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.plot.flag.implementations;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.plot.flag.types.BooleanFlag;
import org.checkerframework.checker.nullness.qual.NonNull;
public class WeavingDeathPlace extends BooleanFlag<WeavingDeathPlace> {
public static final WeavingDeathPlace WEAVING_DEATH_PLACE_TRUE = new WeavingDeathPlace(true);
public static final WeavingDeathPlace WEAVING_DEATH_PLACE_FALSE = new WeavingDeathPlace(false);
private WeavingDeathPlace(boolean value) {
super(value, TranslatableCaption.of("flags.flag_description_weaving_death_place"));
}
@Override
protected WeavingDeathPlace flagOf(@NonNull Boolean value) {
return value ? WEAVING_DEATH_PLACE_TRUE : WEAVING_DEATH_PLACE_FALSE;
}
}

View File

@ -37,7 +37,7 @@ import java.util.List;
public class SinglePlotManager extends PlotManager {
private static final int MAX_COORDINATE = 20000000;
private static final int MAX_COORDINATE = 30000000;
public SinglePlotManager(final @NonNull PlotArea plotArea) {
super(plotArea);

View File

@ -52,7 +52,6 @@ public class ChunkCoordinatorBuilder {
private int initialBatchSize = Settings.QUEUE.INITIAL_BATCH_SIZE;
private boolean unloadAfter = true;
private boolean forceSync = false;
private boolean shouldGen = true;
@Inject
public ChunkCoordinatorBuilder(@NonNull ChunkCoordinatorFactory chunkCoordinatorFactory) {
@ -204,19 +203,6 @@ public class ChunkCoordinatorBuilder {
return this;
}
/**
* Set whether chunks should be generated as part of this operation. Default is true. Disabling this may not be supported
* depending on server implementation. (i.e. setting to false may not actually disable generation as part of this operation
* - this is just a catch-all in case of future differing server implementations; the option will work on Spigot/Paper).
*
* @param shouldGen should generate new chunks or not
* @since 7.5.0
*/
public @NonNull ChunkCoordinatorBuilder shouldGen(final boolean shouldGen) {
this.shouldGen = shouldGen;
return this;
}
public @NonNull ChunkCoordinatorBuilder withProgressSubscriber(ProgressSubscriber progressSubscriber) {
this.progressSubscribers.add(progressSubscriber);
return this;
@ -248,8 +234,7 @@ public class ChunkCoordinatorBuilder {
this.throwableConsumer,
this.unloadAfter,
this.progressSubscribers,
this.forceSync,
this.shouldGen
this.forceSync
);
}

View File

@ -51,7 +51,6 @@ public class DelegateQueueCoordinator extends QueueCoordinator {
if (parent != null) {
this.setForceSync(parent.isForceSync());
this.setShouldGen(parent.isShouldGen());
}
}

View File

@ -45,7 +45,6 @@ public abstract class QueueCoordinator {
private final AtomicBoolean enqueued = new AtomicBoolean();
private boolean forceSync = false;
private boolean shouldGen = true;
@Nullable
private Object chunkObject;
@SuppressWarnings({"unused", "FieldCanBeLocal"})
@ -111,30 +110,6 @@ public abstract class QueueCoordinator {
this.forceSync = forceSync;
}
/**
* Get whether chunks should be generated as part of this operation. Default is true. Disabling this may not be supported
* depending on server implementation. (i.e. setting to false may not actually disable generation as part of this operation
* - this is just a catch-all in case of future differing server implementations; the option will work on Spigot/Paper).
*
* @since 7.5.0
*/
public boolean isShouldGen() {
return shouldGen;
}
/**
* Set whether chunks should be generated as part of this operation. Default is true. Disabling this may not be supported
* depending on server implementation. (i.e. setting to false may not actually disable generation as part of this operation
* - this is just a catch-all in case of future differing server implementations; the option will work on Spigot/Paper).
*
* @param shouldGen should generate new chunks or not
* @since 7.5.0
*/
public void setShouldGen(boolean shouldGen) {
this.shouldGen = shouldGen;
}
/**
* Get the Chunk Object set to the queue
*

View File

@ -18,7 +18,6 @@
*/
package com.plotsquared.core.services.plots;
import cloud.commandframework.services.types.Service;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.plotsquared.core.plot.Plot;
@ -26,6 +25,7 @@ import com.plotsquared.core.plot.PlotAreaType;
import com.plotsquared.core.plot.PlotId;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.services.type.Service;
import java.util.Collections;
import java.util.List;

View File

@ -31,8 +31,6 @@ import com.sk89q.worldedit.world.registry.LegacyMapper;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
/**
* {@link BlockState} related utility methods
*/
@ -45,8 +43,7 @@ public final class BlockUtil {
PARSER_CONTEXT.setRestricted(false);
PARSER_CONTEXT.setPreferringWildcard(false);
PARSER_CONTEXT.setTryLegacy(true);
List<InputParser<BaseBlock>> parsers = WorldEdit.getInstance().getBlockFactory().getParsers();
PARSER = parsers.get(parsers.size() - 1); // Default parser is always at the end
PARSER = WorldEdit.getInstance().getBlockFactory().getParsers().get(0);
}
private BlockUtil() {

View File

@ -25,7 +25,6 @@ import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.events.PlayerAutoPlotEvent;
import com.plotsquared.core.events.PlayerAutoPlotsChosenEvent;
import com.plotsquared.core.events.PlayerBuyPlotEvent;
import com.plotsquared.core.events.PlayerClaimPlotEvent;
import com.plotsquared.core.events.PlayerEnterPlotEvent;
import com.plotsquared.core.events.PlayerLeavePlotEvent;
@ -50,9 +49,7 @@ import com.plotsquared.core.events.PlotUnlinkEvent;
import com.plotsquared.core.events.RemoveRoadEntityEvent;
import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.events.post.PostPlayerAutoPlotEvent;
import com.plotsquared.core.events.post.PostPlayerBuyPlotEvent;
import com.plotsquared.core.events.post.PostPlotChangeOwnerEvent;
import com.plotsquared.core.events.post.PostPlotClearEvent;
import com.plotsquared.core.events.post.PostPlotDeleteEvent;
import com.plotsquared.core.events.post.PostPlotMergeEvent;
import com.plotsquared.core.events.post.PostPlotUnlinkEvent;
@ -60,7 +57,6 @@ import com.plotsquared.core.listener.PlayerBlockEventType;
import com.plotsquared.core.location.Direction;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.OfflinePlotPlayer;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
@ -183,12 +179,6 @@ public class EventDispatcher {
return event;
}
public PostPlotClearEvent callPostPlotClear(PlotPlayer<?> player, Plot plot) {
PostPlotClearEvent event = new PostPlotClearEvent(player, plot);
callEvent(event);
return event;
}
public PlotDeleteEvent callDelete(Plot plot) {
PlotDeleteEvent event = new PlotDeleteEvent(plot);
callEvent(event);
@ -325,17 +315,6 @@ public class EventDispatcher {
return event;
}
public PlayerBuyPlotEvent callPlayerBuyPlot(PlotPlayer<?> player, Plot plot, double price) {
PlayerBuyPlotEvent event = new PlayerBuyPlotEvent(player, plot, price);
eventBus.post(event);
return event;
}
public void callPostPlayerBuyPlot(PlotPlayer<?> player, OfflinePlotPlayer previousOwner, Plot plot,
double price) {
eventBus.post(new PostPlayerBuyPlotEvent(player, previousOwner, plot, price));
}
public void doJoinTask(final PlotPlayer<?> player) {
if (player == null) {
return; //possible future warning message to figure out where we are retrieving null
@ -371,10 +350,7 @@ public class EventDispatcher {
Location location, BlockType blockType, boolean notifyPerms
) {
PlotArea area = location.getPlotArea();
// the interaction target location might be outside a plot area
if (area == null) {
return true;
}
assert area != null;
if (!area.buildRangeContainsY(location.getY()) && !player.hasPermission(Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) {
player.sendMessage(
TranslatableCaption.of("height.height_limit"),
@ -554,7 +530,6 @@ public class EventDispatcher {
)
);
}
return false;
}
default -> {
}

View File

@ -107,7 +107,6 @@ public final class TabCompletions {
}
public static @NonNull List<Command> completePlayersInPlot(
final @NonNull PlotPlayer<?> issuer,
final @NonNull Plot plot,
final @NonNull String input, final @NonNull List<String> existing
) {
@ -116,9 +115,7 @@ public final class TabCompletions {
final List<PlotPlayer<?>> inPlot = plot.getPlayersInPlot();
players = new ArrayList<>(inPlot.size());
for (PlotPlayer<?> player : inPlot) {
if (issuer.canSee(player)) {
players.add(player.getName());
}
players.add(player.getName());
}
cachedCompletionValues.put("inPlot" + plot, players);
}

View File

@ -62,15 +62,6 @@ import java.util.zip.ZipOutputStream;
public abstract class WorldUtil {
/**
* {@return whether the given location is valid in the world}
* @param location the location to check
* @since 7.3.6
*/
public static boolean isValidLocation(Location location) {
return Math.abs(location.getX()) < 30000000 && Math.abs(location.getZ()) < 30000000;
}
/**
* Set the biome in a region
*
@ -177,13 +168,6 @@ public abstract class WorldUtil {
*/
public abstract void getBlock(@NonNull Location location, @NonNull Consumer<BlockState> result);
/**
* Checks if the block smaller as a slab
* @param location Block location
* @return true if it smaller as a slab
*/
public abstract boolean isSmallBlock(@NonNull Location location);
/**
* Get the block at a given location (synchronously)
*

View File

@ -41,7 +41,6 @@ public class EntityCategories {
public static final EntityCategory PROJECTILE = register("projectile");
public static final EntityCategory OTHER = register("other");
public static final EntityCategory PLAYER = register("player");
public static final EntityCategory INTERACTION = register("interaction");
public static EntityCategory register(final String id) {
final EntityCategory entityCategory = new EntityCategory(PlotSquared.platform().worldUtil(), id);

View File

@ -27,17 +27,13 @@ import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.LocaleHolder;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.MetaDataAccess;
import com.plotsquared.core.player.PlayerMetaDataKeys;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
import com.plotsquared.core.plot.flag.implementations.ServerPlotFlag;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.PlayerManager;
import com.plotsquared.core.util.query.PlotQuery;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -99,12 +95,6 @@ public final class PlaceholderRegistry {
}
return Integer.toString(player.getAllowedPlots());
});
this.createPlaceholder("base_plot_count", player -> Integer.toString(PlotQuery.newQuery()
.ownedBy(player)
.whereBasePlot()
.thatPasses(plot -> !DoneFlag.isDone(plot))
.count())
);
this.createPlaceholder("plot_count", player -> Integer.toString(player.getPlotCount()));
this.createPlaceholder("currentplot_alias", (player, plot) -> {
if (plot.getAlias().isEmpty()) {
@ -199,11 +189,6 @@ public final class PlaceholderRegistry {
});
this.createPlaceholder("currentplot_biome", (player, plot) -> plot.getBiomeSynchronous().toString());
this.createPlaceholder("currentplot_size", (player, plot) -> String.valueOf(plot.getConnectedPlots().size()));
this.createPlaceholder("total_grants", player -> {
try (final MetaDataAccess<Integer> metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) {
return Integer.toString(metaDataAccess.get().orElse(0));
}
});
}
/**

View File

@ -125,7 +125,6 @@
"economy.added_balance": "<prefix><gold><money> </gold><gray>has been added to your balance.</gray>",
"economy.removed_balance": "<prefix><gold><money> </gold><gray>has been taken from your balance.</gray>",
"economy.removed_granted_plot": "<prefix><gray>You used <used_grants> plot grant(s), you've got </gray><gold><remaining_grants></gold> <gray>left.</gray>",
"economy.cannot_buy_blocked": "<prefix><red>You are not allowed to buy this plot.</red>",
"setup.choose_generator": "<gold>What generator do you want?</gold>",
"setup.setup_not_started": "<prefix><gold>No setup started.</gold>",
"setup.setup_init": "<prefix><gold>Usage: </gold><gray>/plot setup <value></gray>",
@ -166,7 +165,6 @@
"setup.wall_height": "<gold>Wall height</gold>",
"setup.min_gen_height": "<gold>Minimum height from which to generate (for 1.18+ can be negative).</gold>",
"setup.bedrock_boolean": "<gold>Whether a bedrock layer under the plot should be generated or not</gold>",
"setup.component_below_bedrock_boolean": "<gold>Whether a component change e.g. /plot set walls should edit the bedrock layer or below</gold>",
"setup.singleplotarea_void_world": "<gold>Void world</gold>",
"plotareatype.plot_area_type_normal": "<gray>Standard plot generation</gray>",
"plotareatype.plot_area_type_augmented": "<gray>Plot generation with vanilla terrain</gray>",
@ -390,11 +388,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><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.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.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><world>;<plot></gold><dark_aqua>.</dark_aqua>",
"working.claimed": "<prefix><dark_aqua>You successfully claimed the plot </dark_aqua><gold><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>",
@ -559,7 +557,6 @@
"flags.flag_description_drop_protection": "<gray>Set to `true` to prevent dropped items from being picked up by non-members of the plot.</gray>",
"flags.flag_description_edit_sign": "<gray>Set to `true` to allow editing signs in the plot.</gray>",
"flags.flag_description_feed": "<gray>Specify an interval in seconds and an optional amount by which the players will be fed (amount is 1 by default).</gray>",
"flags.flag_description_fishing": "<gray>Set to `true` to allow guests to use a fishing rod in the plot.</gray>",
"flags.flag_description_forcefield": "<gray>Set to `true` to enable member forcefield in the plot.</gray>",
"flags.flag_description_grass_grow": "<gray>Set to `false` to prevent grass from growing within the plot.</gray>",
"flags.flag_description_hanging_break": "<gray>Set to `true` to allow guests to break hanging objects in the plot.</gray>",
@ -572,7 +569,6 @@
"flags.flag_description_ice_form": "<gray>Set to `true` to allow ice to form in the plot.</gray>",
"flags.flag_description_ice_melt": "<gray>Set to `false` to disable ice melting in the plot.</gray>",
"flags.flag_description_instabreak": "<gray>Set to `true` to allow blocks to be instantaneously broken in survival mode.</gray>",
"flags.flag_description_interaction_interact": "<gray>Set to `true` to allow guests to interact with interaction entities in the plot.</gray>",
"flags.flag_description_invincible": "<gray>Set to `true` to prevent players from taking damage inside the plot.</gray>",
"flags.flag_description_item_drop": "<gray>Set to `false` to prevent items from being dropped inside the plot.</gray>",
"flags.flag_description_kelp_grow": "<gray>Set to `false` to prevent kelp from growing in the plot.</gray>",
@ -607,7 +603,6 @@
"flags.flag_description_tamed_attack": "<gray>Set to `true` to allow guests to attack tamed animals in the plot.</gray>",
"flags.flag_description_tamed_interact": "<gray>Set to `true` to allow guests to interact with tamed animals in the plot.</gray>",
"flags.flag_description_time": "<gray>Set the time in the plot to a fixed value.</gray>",
"flags.flag_description_tile_drop": "<gray>Set to `false` to prevent blocks from dropping items in the plot.</gray>",
"flags.flag_description_titles": "<gray>Set to `false` to disable plot titles. Can be set to: `none` (to inherit world settings), `true`, or `false`</gray>",
"flags.flag_description_title": "<gray>Set the pop-up title's title and subtitle. Format: /plot flag set title \"A title\" \"The subtitle\"</gray>",
"flags.flag_description_use": "<gray>Define a list of materials players should be able to interact with in the plot.</gray>",
@ -629,7 +624,6 @@
"flags.flag_description_prevent_creative_copy": "<gray>Prevents people from copying item NBT data in the plot unless they're added as members.</gray>",
"flags.flag_description_leaf_decay": "<gray>Set to `false` to prevent leaves from decaying.",
"flags.flag_description_projectiles": "<gray>Prevents guests from shooting projectiles on the plot when set to false.</gray>",
"flags.flag_description_weaving_death_place": "<gray>Set to `false` to prevent spawning of cobwebs by the Weaving status effect on the death of an entity.</gray>",
"flags.flag_description_beacon_effect": "<gray>Enables beacon effects on the plot.</gray>",
"flags.flag_error_boolean": "Flag value must be a boolean (true | false).",
"flags.flag_error_enum": "Must be one of: <list>",

View File

@ -1,6 +1,5 @@
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
@ -8,12 +7,13 @@ 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.publish)
alias(libs.plugins.nexus)
eclipse
idea
@ -22,7 +22,7 @@ plugins {
}
group = "com.intellectualsites.plotsquared"
version = "7.5.3-SNAPSHOT"
version = "7.3.2-SNAPSHOT"
if (!File("$rootDir/.git").exists()) {
logger.lifecycle("""
@ -41,6 +41,16 @@ 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")
@ -58,7 +68,7 @@ subprojects {
apply {
plugin<JavaPlugin>()
plugin<JavaLibraryPlugin>()
plugin<com.vanniktech.maven.publish.MavenPublishPlugin>()
plugin<MavenPublishPlugin>()
plugin<ShadowPlugin>()
plugin<SpotlessPlugin>()
plugin<SigningPlugin>()
@ -69,13 +79,13 @@ subprojects {
dependencies {
// Tests
testImplementation("org.junit.jupiter:junit-jupiter:5.12.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.12.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.1")
}
plugins.withId("java") {
the<JavaPluginExtension>().toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
languageVersion.set(JavaLanguageVersion.of(17))
}
}
@ -84,7 +94,7 @@ subprojects {
}
configurations.all {
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
spotless {
@ -97,13 +107,18 @@ subprojects {
}
}
java {
withSourcesJar()
withJavadocJar()
}
val javaComponent = components["java"] as AdhocComponentWithVariants
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) {
skip()
}
signing {
if (!project.hasProperty("skip.signing") && !version.toString().endsWith("-SNAPSHOT")) {
if (!version.toString().endsWith("-SNAPSHOT")) {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
@ -112,67 +127,66 @@ subprojects {
}
}
mavenPublishing {
coordinates(
groupId = "$group",
artifactId = project.name,
version = "${project.version}",
)
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
pom {
name.set(project.name)
description.set("PlotSquared, a land and world management plugin for Minecraft.")
url.set("https://github.com/IntellectualSites/PlotSquared")
pom {
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")
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")
}
}
}
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)
}
}
@ -180,6 +194,7 @@ subprojects {
compileJava {
options.compilerArgs.add("-parameters")
options.isDeprecation = true
options.encoding = "UTF-8"
}
@ -194,10 +209,14 @@ subprojects {
test {
useJUnitPlatform()
}
}
}
withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
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/"))
}
}
}
@ -206,7 +225,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")
val supportedVersions = listOf("1.16.5", "1.17.1", "1.18.2", "1.19.4", "1.20.1", "1.20.4")
tasks {
register("cacheLatestFaweArtifact") {
val lastSuccessfulBuildUrl = uri("https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/api/json").toURL()

View File

@ -1,43 +1,45 @@
[versions]
# Platform expectations
paper = "1.20.4-R0.1-SNAPSHOT"
paper = "1.20.2-R0.1-SNAPSHOT"
guice = "7.0.0"
spotbugs = "4.9.3"
checkerqual = "3.49.2"
spotbugs = "4.8.3"
checkerqual = "3.42.0"
gson = "2.10"
guava = "31.1-jre"
snakeyaml = "2.0"
adventure = "4.20.0"
adventure-bukkit = "4.3.4"
adventure = "4.15.0"
adventure-bukkit = "4.3.2"
log4j = "2.19.0"
# Plugins
worldedit = "7.2.20"
fawe = "2.13.0"
placeholderapi = "2.11.6"
worldedit = "7.2.18"
fawe = "2.8.3"
placeholderapi = "2.11.5"
luckperms = "5.4"
essentialsx = "2.21.0"
essentialsx = "2.20.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.2"
squirrelid = "0.3.2"
paster = "1.1.6"
bstats = "3.1.0"
paster = "1.1.5"
bstats = "3.0.2"
paperlib = "1.0.8"
informative-annotations = "1.5"
informative-annotations = "1.4"
vault = "1.7.1"
serverlib = "2.3.7"
serverlib = "2.3.4"
cloud = "2.0.0-beta.1"
cloudRequirements = "1.0.0-beta.1"
# Gradle plugins
shadow = "8.3.6"
shadow = "8.1.1"
grgit = "4.1.1"
spotless = "7.0.3"
publish = "0.31.0"
runPaper = "2.3.1"
spotless = "6.23.3"
nexus = "1.3.0"
runPaper = "2.2.2"
[libraries]
# Platform expectations
@ -66,20 +68,25 @@ faweBukkit = { group = "com.fastasyncworldedit", name = "FastAsyncWorldEdit-Bukk
# Third party
prtree = { group = "com.intellectualsites.prtree", name = "PRTree", version.ref = "prtree" }
aopalliance = { group = "aopalliance", name = "aopalliance", version.ref = "aopalliance" }
cloudServices = { group = "cloud.commandframework", name = "cloud-services", version.ref = "cloud-services" }
cloudServices = { group = "org.incendo", name = "cloud-services", version.ref = "cloud-services" }
mvdwapi = { group = "com.intellectualsites.mvdwplaceholderapi", name = "MVdWPlaceholderAPI", version.ref = "mvdwapi" }
squirrelid = { group = "org.enginehub", name = "squirrelid", version.ref = "squirrelid" }
arkitektonika = { group = "com.intellectualsites.arkitektonika", name = "Arkitektonika-Client", version.ref = "arkitektonika" }
paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref = "paster" }
bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" }
bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
informativeAnnotations = { group = "com.intellectualsites.informative-annotations", name = "informative-annotations", version.ref = "informative-annotations" }
paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" }
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" }
cloud = { group = "org.incendo", name = "cloud-core", version.ref = "cloud" }
cloudPaper = { group = "org.incendo", name = "cloud-paper", version.ref = "cloud" }
cloudMinecraftExtras = { group = "org.incendo", name = "cloud-minecraft-extras", version.ref = "cloud" }
cloudRequirements = { group = "org.incendo", name = "cloud-processors-requirements", version.ref = "cloudRequirements" }
[plugins]
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
publish = { id = "com.vanniktech.maven.publish", version.ref = "publish" }
nexus = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus" }
runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" }

Binary file not shown.

View File

@ -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.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

8
gradlew vendored
View File

@ -15,8 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -57,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -86,7 +84,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -205,7 +203,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.

22
gradlew.bat vendored
View File

@ -13,8 +13,6 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@ -45,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
@ -59,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail

Some files were not shown because too many files have changed in this diff Show More