Compare commits

..

1 Commits

16 changed files with 81 additions and 197 deletions

View File

@ -513,10 +513,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
this.backgroundPipeline.registerService(essentialsUUIDService);
}
if (Settings.UUID.IMPROMPTU_SERVICE_MOJANG_API) {
final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT);
this.impromptuPipeline.registerService(impromptuMojangService);
}
final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT);
this.impromptuPipeline.registerService(impromptuMojangService);
final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT);
this.backgroundPipeline.registerService(backgroundMojangService);
} else {

View File

@ -80,8 +80,7 @@ final class DelegatePlotGenerator extends IndependentPlotGenerator {
result.setBiome(x, z, BukkitAdapter.adapt(biome));
}
//do not annotate with Override until we discontinue support for 1.4.4 (we no longer support 1.4.4)
@Override
//do not annotate with Override until we discontinue support for 1.4.4
public void setBiome(int x, int y, int z, @NonNull Biome biome) {
result.setBiome(x, z, BukkitAdapter.adapt(biome));

View File

@ -44,7 +44,6 @@ 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.DoneFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.Permissions;
import net.kyori.adventure.text.minimessage.Template;
@ -353,15 +352,13 @@ public class PaperListener implements Listener {
event.setCancelled(true);
}
} else if (!plot.isAdded(pp.getUUID())) {
if (!plot.getFlag(ProjectilesFlag.class)) {
if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
pp.sendMessage(
TranslatableCaption.of("permission.no_permission_event"),
Template.of("node", String.valueOf(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER))
);
entity.remove();
event.setCancelled(true);
}
if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
pp.sendMessage(
TranslatableCaption.of("permission.no_permission_event"),
Template.of("node", String.valueOf(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER))
);
entity.remove();
event.setCancelled(true);
}
}
}

View File

@ -35,7 +35,6 @@ 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.ProjectilesFlag;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.Permissions;
import net.kyori.adventure.text.minimessage.Template;
@ -129,15 +128,13 @@ public class ProjectileEventListener implements Listener {
event.setCancelled(true);
}
} else if (!plot.isAdded(pp.getUUID())) {
if (!plot.getFlag(ProjectilesFlag.class)) {
if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
pp.sendMessage(
TranslatableCaption.of("permission.no_permission_event"),
Template.of("node", String.valueOf(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER))
);
entity.remove();
event.setCancelled(true);
}
if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
pp.sendMessage(
TranslatableCaption.of("permission.no_permission_event"),
Template.of("node", String.valueOf(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER))
);
entity.remove();
event.setCancelled(true);
}
}
}
@ -165,7 +162,7 @@ public class ProjectileEventListener implements Listener {
return;
}
if (plot.isAdded(pp.getUUID()) || Permissions
.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_OTHER) || plot.getFlag(ProjectilesFlag.class)) {
.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_OTHER)) {
return;
}
entity.remove();

View File

@ -51,7 +51,6 @@ import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.block.Block;
import org.bukkit.block.Container;
import org.bukkit.block.data.BlockData;
@ -267,13 +266,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
} catch (WorldEditException ignored) {
// Fallback to not so nice method
BlockData blockData = BukkitAdapter.adapt(block);
Block existing;
// Assume a chunk object has been given only when it should have been.
if (getChunkObject() instanceof Chunk chunkObject) {
existing = chunkObject.getBlock(x & 15, y, z & 15);
} else {
existing = getBukkitWorld().getBlockAt(x, y, z);
}
Block existing = getBukkitWorld().getBlockAt(x, y, z);
final BlockState existingBaseBlock = BukkitAdapter.adapt(existing.getBlockData());
if (BukkitBlockUtil.get(existing).equals(existingBaseBlock) && existing.getBlockData().matches(blockData)) {
return;
@ -289,7 +282,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
CompoundTag tag = block.getNbtData();
StateWrapper sw = new StateWrapper(tag);
sw.restoreTag(existing);
sw.restoreTag(getWorld().getName(), existing.getX(), existing.getY(), existing.getZ());
}
}
}

View File

@ -44,7 +44,6 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.ArrayList;
import java.util.HashMap;
@ -167,32 +166,14 @@ public class StateWrapper {
return str;
}
/**
* Restore the TileEntity data to the given world at the given coordinates.
*
* @param worldName World name
* @param x x position
* @param y y position
* @param z z position
* @return true if successful
*/
@SuppressWarnings("deprecation") // #setLine is needed for Spigot compatibility
public boolean restoreTag(String worldName, int x, int y, int z) {
World world = BukkitUtil.getWorld(worldName);
if (world == null) {
if (this.tag == null) {
return false;
}
return restoreTag(world.getBlockAt(x, y, z));
}
/**
* Restore the TileEntity data to the given block
*
* @param block Block to restore to
* @return true if successful
*/
@SuppressWarnings("deprecation") // #setLine is needed for Spigot compatibility
public boolean restoreTag(@NonNull Block block) {
if (this.tag == null) {
World world = BukkitUtil.getWorld(worldName);
Block block = world.getBlockAt(x, y, z);
if (block == null) {
return false;
}
org.bukkit.block.BlockState state = block.getState();

View File

@ -889,8 +889,8 @@ public class PlotSquared {
e.printStackTrace();
}
LOGGER.info("| generator: {}>{}", baseGenerator, areaGen);
LOGGER.info("| plot world: {}", pa.getClass().getCanonicalName());
LOGGER.info("| manager: {}", pa.getPlotManager().getClass().getCanonicalName());
LOGGER.info("| plot world: {}", pa);
LOGGER.info("| manager: {}", pa);
LOGGER.info("Note: Area created for cluster '{}' (invalid or old configuration?)", name);
areaGen.getPlotGenerator().initialize(pa);
areaGen.augment(pa);
@ -906,13 +906,6 @@ public class PlotSquared {
throw new IllegalArgumentException("Invalid Generator: " + gen_string);
}
PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, null, null, null);
LOGGER.info("- generator: {}>{}", baseGenerator, areaGen);
LOGGER.info("- plot world: {}", pa.getClass().getCanonicalName());
LOGGER.info("- plot area manager: {}", pa.getPlotManager().getClass().getCanonicalName());
if (!this.worldConfiguration.contains(path)) {
this.worldConfiguration.createSection(path);
worldSection = this.worldConfiguration.getConfigurationSection(path);
}
pa.saveConfiguration(worldSection);
pa.loadDefaultConfiguration(worldSection);
try {
@ -920,6 +913,9 @@ public class PlotSquared {
} catch (IOException e) {
e.printStackTrace();
}
LOGGER.info("- generator: {}>{}", baseGenerator, areaGen);
LOGGER.info("- plot world: {}", pa);
LOGGER.info("- plot area manager: {}", pa.getPlotManager());
areaGen.getPlotGenerator().initialize(pa);
areaGen.augment(pa);
addPlotArea(pa);

View File

@ -32,7 +32,6 @@ import com.plotsquared.core.configuration.caption.Caption;
import com.plotsquared.core.configuration.caption.CaptionHolder;
import com.plotsquared.core.configuration.caption.Templates;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.database.DBFunc;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
@ -40,7 +39,6 @@ import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.expiration.ExpireManager;
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
import com.plotsquared.core.plot.flag.implementations.PriceFlag;
import com.plotsquared.core.plot.flag.implementations.ServerPlotFlag;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.MathMan;
@ -420,7 +418,7 @@ public class ListCmd extends SubCommand {
Caption color;
if (plot.getOwner() == null) {
color = TranslatableCaption.of("info.plot_list_no_owner");
} else if (plot.isOwner(player.getUUID()) || plot.getOwner().equals(DBFunc.EVERYONE)) {
} else if (plot.isOwner(player.getUUID())) {
color = TranslatableCaption.of("info.plot_list_owned_by");
} else if (plot.isAdded(player.getUUID())) {
color = TranslatableCaption.of("info.plot_list_added_to");
@ -458,60 +456,37 @@ public class ListCmd extends SubCommand {
String prefix = "";
String online = TranslatableCaption.of("info.plot_list_player_online").getComponent(player);
String offline = TranslatableCaption.of("info.plot_list_player_offline").getComponent(player);
String unknown = TranslatableCaption.of("info.plot_list_player_unknown").getComponent(player);
String server = TranslatableCaption.of("info.plot_list_player_server").getComponent(player);
String everyone = TranslatableCaption.of("info.plot_list_player_everyone").getComponent(player);
TextComponent.Builder builder = Component.text();
if (plot.getFlag(ServerPlotFlag.class)) {
Template serverTemplate = Template.of(
"info.server",
TranslatableCaption.of("info.server").getComponent(player)
);
builder.append(MINI_MESSAGE.parse(server, serverTemplate));
} else {
try {
final List<UUIDMapping> names = PlotSquared.get().getImpromptuUUIDPipeline().getNames(plot.getOwners())
.get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS);
for (final UUIDMapping uuidMapping : names) {
PlotPlayer<?> pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuidMapping.getUuid());
Template prefixTemplate = Template.of("prefix", prefix);
Template playerTemplate = Template.of("player", uuidMapping.getUsername());
if (pp != null) {
builder.append(MINI_MESSAGE.parse(online, prefixTemplate, playerTemplate));
} else if (uuidMapping.getUsername().equalsIgnoreCase("unknown")) {
Template unknownTemplate = Template.of(
"info.unknown",
TranslatableCaption.of("info.unknown").getComponent(player)
);
builder.append(MINI_MESSAGE.parse(unknown, unknownTemplate));
} else if (uuidMapping.getUuid().equals(DBFunc.EVERYONE)) {
Template everyoneTemplate = Template.of(
"info.everyone",
TranslatableCaption.of("info.everyone").getComponent(player)
);
builder.append(MINI_MESSAGE.parse(everyone, everyoneTemplate));
} else {
builder.append(MINI_MESSAGE.parse(offline, prefixTemplate, playerTemplate));
}
prefix = ", ";
try {
final List<UUIDMapping> names = PlotSquared.get().getImpromptuUUIDPipeline().getNames(plot.getOwners())
.get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS);
for (final UUIDMapping uuidMapping : names) {
PlotPlayer<?> pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuidMapping.getUuid());
Template prefixTemplate = Template.of("prefix", prefix);
Template playerTemplate = Template.of("player", uuidMapping.getUsername());
if (pp != null) {
builder.append(MINI_MESSAGE.parse(online, prefixTemplate, playerTemplate));
} else {
builder.append(MINI_MESSAGE.parse(offline, prefixTemplate, playerTemplate));
}
} catch (InterruptedException | ExecutionException e) {
final StringBuilder playerBuilder = new StringBuilder();
final Iterator<UUID> uuidIterator = plot.getOwners().iterator();
while (uuidIterator.hasNext()) {
final UUID uuid = uuidIterator.next();
playerBuilder.append(uuid);
if (uuidIterator.hasNext()) {
playerBuilder.append(", ");
}
}
player.sendMessage(
TranslatableCaption.of("errors.invalid_player"),
Templates.of("value", playerBuilder.toString())
);
} catch (TimeoutException e) {
player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout"));
prefix = ", ";
}
} catch (InterruptedException | ExecutionException e) {
final StringBuilder playerBuilder = new StringBuilder();
final Iterator<UUID> uuidIterator = plot.getOwners().iterator();
while (uuidIterator.hasNext()) {
final UUID uuid = uuidIterator.next();
playerBuilder.append(uuid);
if (uuidIterator.hasNext()) {
playerBuilder.append(", ");
}
}
player.sendMessage(
TranslatableCaption.of("errors.invalid_player"),
Templates.of("value", playerBuilder.toString())
);
} catch (TimeoutException e) {
player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout"));
}
Template players = Template.of("players", builder.asComponent());
caption.set(TranslatableCaption.of("info.plot_list_item"));

View File

@ -249,9 +249,6 @@ public class Settings extends Config {
public static int UUID_CACHE_SIZE = 100000;
@Comment("Rate limit (per 10 minutes) for background UUID fetching from the Mojang API")
public static int BACKGROUND_LIMIT = 200;
@Comment("Whether the Mojang API service is enabled for impromptu api calls. If false only the Background task will use" +
" http requests to fill the UUID cache (requires restart)")
public static boolean IMPROMPTU_SERVICE_MOJANG_API = true;
@Comment("Rate limit (per 10 minutes) for random UUID fetching from the Mojang API")
public static int IMPROMPTU_LIMIT = 300;
@Comment("Timeout (in milliseconds) for non-blocking UUID requests (mostly commands)")
@ -694,7 +691,6 @@ public class Settings extends Config {
@Comment({"If blocks at the edges of queued operations should be set causing updates",
" - Slightly slower, but prevents issues such as fences left connected to nothing"})
public static boolean UPDATE_EDGES = true;
}
@Comment("Settings related to tab completion")

View File

@ -1420,7 +1420,15 @@ public class Plot {
0
);
}
Location location = toHomeLocation(bottom, home);
Location location = Location
.at(
bottom.getWorldName(),
bottom.getX() + home.getX(),
bottom.getY() + home.getY(),
bottom.getZ() + home.getZ(),
home.getYaw(),
home.getPitch()
);
if (!this.worldUtil.getBlockSynchronous(location).getBlockType().getMaterial().isAir()) {
location = location.withY(
Math.max(1 + this.worldUtil.getHighestBlockSynchronous(
@ -1453,7 +1461,15 @@ public class Plot {
return;
}
Location bottom = this.getBottomAbs();
Location location = toHomeLocation(bottom, home);
Location location = Location
.at(
bottom.getWorldName(),
bottom.getX() + home.getX(),
home.getY(), // y is absolute
bottom.getZ() + home.getZ(),
home.getYaw(),
home.getPitch()
);
this.worldUtil.getBlock(location, block -> {
if (!block.getBlockType().getMaterial().isAir()) {
this.worldUtil.getHighestBlock(this.getWorldName(), location.getX(), location.getZ(),
@ -1466,17 +1482,6 @@ public class Plot {
}
}
private Location toHomeLocation(Location bottom, BlockLoc relativeHome) {
return Location.at(
bottom.getWorldName(),
bottom.getX() + relativeHome.getX(),
relativeHome.getY(), // y is absolute
bottom.getZ() + relativeHome.getZ(),
relativeHome.getYaw(),
relativeHome.getPitch()
);
}
/**
* Sets the home location
*

View File

@ -93,7 +93,6 @@ import com.plotsquared.core.plot.flag.implementations.PlayerInteractFlag;
import com.plotsquared.core.plot.flag.implementations.PlotTitleFlag;
import com.plotsquared.core.plot.flag.implementations.PreventCreativeCopyFlag;
import com.plotsquared.core.plot.flag.implementations.PriceFlag;
import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag;
import com.plotsquared.core.plot.flag.implementations.PveFlag;
import com.plotsquared.core.plot.flag.implementations.PvpFlag;
import com.plotsquared.core.plot.flag.implementations.RedstoneFlag;
@ -199,7 +198,6 @@ public final class GlobalFlagContainer extends FlagContainer {
this.addFlag(VehicleUseFlag.VEHICLE_USE_FALSE);
this.addFlag(VillagerInteractFlag.VILLAGER_INTERACT_FALSE);
this.addFlag(VineGrowFlag.VINE_GROW_TRUE);
this.addFlag(ProjectilesFlag.PROJECTILES_FALSE);
// Double flags
this.addFlag(PriceFlag.PRICE_NOT_BUYABLE);

View File

@ -1,46 +0,0 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* PlotSquared plot management system for Minecraft
* Copyright (C) 2014 - 2022 IntellectualSites
*
* 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 ProjectilesFlag extends BooleanFlag<ProjectilesFlag> {
public static final ProjectilesFlag PROJECTILES_TRUE = new ProjectilesFlag(true);
public static final ProjectilesFlag PROJECTILES_FALSE = new ProjectilesFlag(false);
private ProjectilesFlag(boolean value){
super(value, TranslatableCaption.of("flags.flag_description_projectiles"));
}
@Override
protected ProjectilesFlag flagOf(@NonNull final Boolean value) {
return value ? PROJECTILES_TRUE : PROJECTILES_FALSE;
}
}

View File

@ -143,8 +143,7 @@ public abstract class QueueCoordinator {
}
/**
* Set a chunk object (e.g. the Bukkit Chunk object) to the queue. This will be used as fallback in case of WNA failure.
* Should ONLY be used in specific cases (i.e. generation, where a chunk is being populated)
* Set a chunk object (e.g. the Bukkit Chunk object) to the queue
*
* @param chunkObject chunk object. Usually the implementation-specific chunk (e.g. bukkit Chunk)
*/

View File

@ -381,9 +381,6 @@
"info.plot_list_default": "<gold><plot></gold>",
"info.plot_list_player_online": "<dark_aqua><prefix></dark_aqua><hover:show_text:\"<dark_aqua>Online</dark_aqua>\"><gold><player></gold></hover>",
"info.plot_list_player_offline": "<dark_aqua><prefix></dark_aqua><hover:show_text:\"<dark_gray>Offline</dark_gray>\"><gold><player></gold></hover>",
"info.plot_list_player_unknown": "<hover:show_text:\"<red>The owner of this plot is unknown</red>\"><white><info.unknown></white></hover>",
"info.plot_list_player_server": "<hover:show_text:\"<red>The plot is owned by the server</red>\"><white><info.server></white></hover>",
"info.plot_list_player_everyone": "<hover:show_text:\"<blue>The plot is owned by everyone</blue>\"><white><info.everyone></white></hover>",
"info.area_info_format": "<header>\n<reset><gold>Name: </gold><gray><name></gray>\n<gold>Type: </gold><gray><type></gray>\n<gold>Terrain: </gold><gray><terrain></gray>\n<gold>Usage: </gold><gray><usage>%</gray>\n<gold>Claimed: </gold><gray><claimed></gray>\n<gold>Clusters: </gold><gray><clusters></gray>\n<gold>Region: </gold><gray><region></gray>\n<gold>Generator: </gold><gray><generator></gray>\n<footer>",
"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>",
@ -616,7 +613,6 @@
"flags.flag_description_lectern_read_book": "<gray>Prevent players taking books from lecterns.</gray>",
"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_error_boolean": "Flag value must be a boolean (true | false).",
"flags.flag_error_enum": "Must be one of: <list>",
"flags.flag_error_integer": "Flag value must be a whole positive number.",

View File

@ -18,7 +18,7 @@ plugins {
idea
}
version = "6.7.1-SNAPSHOT"
version = "6.6.4-SNAPSHOT"
allprojects {
group = "com.plotsquared"
@ -140,7 +140,7 @@ allprojects {
}
developer {
id.set("NotMyFault")
name.set("Alexander Brandes")
name.set("NotMyFault")
organization.set("IntellectualSites")
email.set("contact@notmyfault.dev")
}

View File

@ -8,7 +8,7 @@ guava = "31.0.1-jre" # Version set by Minecraft
paper = "1.18.1-R0.1-SNAPSHOT"
checker-qual = "3.22.0"
guice = "5.1.0"
spotbugs = "4.7.0"
spotbugs = "4.6.0"
snakeyaml = "1.30" # Version set by Bukkit
# Adventure & MiniMessage