diff --git a/Bukkit/build.gradle.kts b/Bukkit/build.gradle.kts index 19e48b218..04a2db3fa 100644 --- a/Bukkit/build.gradle.kts +++ b/Bukkit/build.gradle.kts @@ -53,6 +53,9 @@ dependencies { // Adventure implementation(libs.adventureBukkit) + + // Cloud + implementation(libs.cloudPaper) } tasks.processResources { @@ -77,6 +80,7 @@ tasks.named("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") diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index 8aa3fb7c0..d2d207a18 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -28,6 +28,7 @@ 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; @@ -64,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; @@ -83,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; @@ -293,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() ); @@ -388,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 diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/commands/BukkitSenderMapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/commands/BukkitSenderMapper.java new file mode 100644 index 000000000..1474f9a99 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/commands/BukkitSenderMapper.java @@ -0,0 +1,50 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> { + + @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(); + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/CloudModule.java b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/CloudModule.java new file mode 100644 index 000000000..87c16642c --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/CloudModule.java @@ -0,0 +1,99 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> commandManager = new PaperCommandManager>( + 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, CommandRequirement> requirementPostprocessor = + RequirementPostprocessor.of(CommandRequirement.REQUIREMENTS_KEY, new PlotSquaredRequirementFailureHandler()); + commandManager.registerCommandPostProcessor(requirementPostprocessor); + + // TODO(City): Override parsing errors using MM parsing. + MinecraftExceptionHandler.>create(PlotPlayer::getAudience) + .defaultHandlers() + .decorator((ctx, component) -> TranslatableCaption.of("core.prefix"). + toComponent(ctx.context().sender()) + .append(component)) + .registerTo(commandManager); + + bind(Key.get(new TypeLiteral>>() {})).toInstance(commandManager); + } +} diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index a12fe2ad2..7e1dd24eb 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -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") diff --git a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java index 958468098..65980e677 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java +++ b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java @@ -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; diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index 230ed9e3a..8008c3b53 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -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 plots = this.servicePipeline .pump(new AutoQuery(player, null, sizeX, sizeZ, plotarea)) .through(AutoService.class) - .getResult(); + .complete(); plots = this.eventDispatcher.callAutoPlotsChosen(player, plots).getPlots(); diff --git a/Core/src/main/java/com/plotsquared/core/commands/CommandRequirement.java b/Core/src/main/java/com/plotsquared/core/commands/CommandRequirement.java new file mode 100644 index 000000000..e5ea95ee5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/CommandRequirement.java @@ -0,0 +1,98 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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, CommandRequirement> { + + /** + * The key used to store the requirements in the {@link org.incendo.cloud.meta.CommandMeta}. + */ + CloudKey, CommandRequirement>> REQUIREMENTS_KEY = CloudKey.of( + "requirements", + new TypeToken, 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> context) { + return context.sender().hasPermission(permission) || thisRequirement.evaluateRequirement(context); + } + }; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/CommonCommandRequirement.java b/Core/src/main/java/com/plotsquared/core/commands/CommonCommandRequirement.java new file mode 100644 index 000000000..8f4708bdf --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/CommonCommandRequirement.java @@ -0,0 +1,81 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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>> predicate; + private final List<@NonNull CommandRequirement> parents; + + CommonCommandRequirement( + final @NonNull TranslatableCaption failureCaption, + final @NonNull Predicate>> 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> context) { + return this.predicate.test(context); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCaptionProvider.java b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCaptionProvider.java new file mode 100644 index 000000000..737cbdc57 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCaptionProvider.java @@ -0,0 +1,50 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> { + + 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; + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandBean.java b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandBean.java new file mode 100644 index 000000000..37989cba7 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandBean.java @@ -0,0 +1,78 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> { + + private final RequirementApplicable.RequirementApplicableFactory, 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}. + * + *

This should be implemented by abstract classes that extend {@link PlotSquaredCommandBean} to offer shared behavior + * for a subset of plot commands.

+ * + * @param builder the builder + * @return the prepared builder + */ + protected Command.@NonNull Builder> prepare(final Command.@NonNull Builder> builder) { + return builder; + } + + @Override + protected final @NonNull CommandProperties properties() { + return CommandProperties.of("platsquared", "plat"); + } + + @Override + protected final Command.@NonNull Builder> configure(final Command.@NonNull Builder> 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> configurePlotCommand( + Command.@NonNull Builder> builder + ); +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandManager.java b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandManager.java new file mode 100644 index 000000000..ad5ec2d4e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandManager.java @@ -0,0 +1,74 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> commandManager; + private final Injector injector; + + @Inject + public PlotSquaredCommandManager( + final @NonNull CommandManager> 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 commands = + this.injector.getInstance(Key.get(new TypeLiteral>() {})); + commands.forEach(command -> this.commandManager().command(command)); + } + + /** + * Returns the command manager. + * + * @return the command manager + */ + public @NonNull CommandManager> 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)); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandMeta.java b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandMeta.java new file mode 100644 index 000000000..0234b2c7c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredCommandMeta.java @@ -0,0 +1,36 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +package com.plotsquared.core.commands; + +import com.plotsquared.core.command.CommandCategory; +import org.incendo.cloud.key.CloudKey; + +/** + * Shared {@link org.incendo.cloud.meta.CommandMeta command meta} keys. + */ +public final class PlotSquaredCommandMeta { + + /** + * Key that determines what {@link CommandCategory category} a command belongs to. + */ + public static final CloudKey META_CATEGORY = CloudKey.of("category", CommandCategory.class); + + private PlotSquaredCommandMeta() { + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredRequirementFailureHandler.java b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredRequirementFailureHandler.java new file mode 100644 index 000000000..34605924e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/PlotSquaredRequirementFailureHandler.java @@ -0,0 +1,35 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +package com.plotsquared.core.commands; + +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 final class PlotSquaredRequirementFailureHandler implements RequirementFailureHandler, CommandRequirement> { + + @Override + public void handleFailure( + final @NonNull CommandContext> context, + final @NonNull CommandRequirement requirement + ) { + context.sender().sendMessage(requirement.failureCaption(), requirement.tagResolvers()); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagAddCommand.java b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagAddCommand.java new file mode 100644 index 000000000..3e5b53a36 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagAddCommand.java @@ -0,0 +1,120 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken>() {}); + private static final CloudKey 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> configurePlotCommand( + final Command.@NonNull Builder> 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> 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() + ); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagCommandBean.java b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagCommandBean.java new file mode 100644 index 000000000..cc0435519 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagCommandBean.java @@ -0,0 +1,139 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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 "." 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, ?> 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> prepare(final Command.@NonNull Builder> builder) { + return builder.literal("flag"); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagInfoCommand.java b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagInfoCommand.java new file mode 100644 index 000000000..019da916b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagInfoCommand.java @@ -0,0 +1,88 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken>() {}); + + @Override + protected Command.@NonNull Builder> configurePlotCommand(final Command.@NonNull Builder> builder) { + return builder.literal("info") + .required(COMPONENT_FLAG, plotFlagParser(PlotFlagParser.FlagSource.GLOBAL)); + } + + @Override + public void execute(final @NonNull CommandContext> 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")); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagListCommand.java b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagListCommand.java new file mode 100644 index 000000000..215685b52 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagListCommand.java @@ -0,0 +1,93 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> configurePlotCommand( + final Command.@NonNull Builder> builder + ) { + return builder.literal("list"); + } + + @Override + public void execute(final @NonNull CommandContext> commandContext) { + final PlotPlayer player = commandContext.sender(); + + final Map> flags = new HashMap<>(); + for (PlotFlag plotFlag : GlobalFlagContainer.getInstance().getRecognizedPlotFlags()) { + if (plotFlag instanceof InternalFlag) { + continue; + } + final Component category = plotFlag.getFlagCategory().toComponent(player); + final Collection flagList = flags.computeIfAbsent(category, k -> new ArrayList<>()); + flagList.add(plotFlag.getName()); + } + + for (final Map.Entry> 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 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()))); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagRemoveCommand.java b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagRemoveCommand.java new file mode 100644 index 000000000..1245c43ea --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagRemoveCommand.java @@ -0,0 +1,171 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken>() {}); + private static final CloudKey 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> configurePlotCommand( + final Command.@NonNull Builder> 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> 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() + ); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagSetCommand.java b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagSetCommand.java new file mode 100644 index 000000000..b8790cde6 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/command/setting/flag/FlagSetCommand.java @@ -0,0 +1,110 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> COMPONENT_FLAG = CloudKey.of("flag", new TypeToken>() {}); + private static final CloudKey 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> configurePlotCommand( + final Command.@NonNull Builder> 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> 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() + ); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/injection/PlotInjector.java b/Core/src/main/java/com/plotsquared/core/commands/injection/PlotInjector.java new file mode 100644 index 000000000..23a3c2e89 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/injection/PlotInjector.java @@ -0,0 +1,42 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +package com.plotsquared.core.commands.injection; + +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; + +/** + * {@link ParameterInjector} that returns the current plot of the player. + */ +public final class PlotInjector implements ParameterInjector, Plot> { + + @Override + public @Nullable Plot create( + final @NonNull CommandContext> context, + final @NonNull AnnotationAccessor annotationAccessor + ) { + // TODO: Allow for overriding for console. + return context.sender().getCurrentPlot(); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/parser/PlotFlagParser.java b/Core/src/main/java/com/plotsquared/core/commands/parser/PlotFlagParser.java new file mode 100644 index 000000000..41077f140 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/parser/PlotFlagParser.java @@ -0,0 +1,158 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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, PlotFlag>, + BlockingSuggestionProvider> { + + /** + * 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, PlotFlag> plotFlagParser(final @NonNull FlagSource source) { + return ParserDescriptor.of(new PlotFlagParser(source), new TypeToken>() { + }); + } + + 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> 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, FlagContainer> containerFunction; + private final boolean storedOnly; + + FlagSource(final @NonNull Function, 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()); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/commands/suggestions/FlagValueSuggestionProvider.java b/Core/src/main/java/com/plotsquared/core/commands/suggestions/FlagValueSuggestionProvider.java new file mode 100644 index 000000000..2eba3716c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/commands/suggestions/FlagValueSuggestionProvider.java @@ -0,0 +1,86 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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> { + + private final CloudKey> 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> flagKey) { + this.flagKey = Objects.requireNonNull(flagKey, "flagKey"); + } + + @Override + public @NonNull Iterable<@NonNull String> stringSuggestions( + @NonNull final CommandContext> context, + @NonNull final CommandInput input + ) { + final PlotFlag plotFlag = context.getOrDefault(this.flagKey, null); + if (plotFlag == null) { + return List.of(); + } + final Collection completions = plotFlag.getTabCompletions(); + if (plotFlag instanceof ListFlag && input.peekString().contains(",")) { + final String[] split = input.peekString().split(","); + final List 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; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/configuration/caption/TranslatableCaption.java b/Core/src/main/java/com/plotsquared/core/configuration/caption/TranslatableCaption.java index 18a2c9fca..28e1aec43 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/caption/TranslatableCaption.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/caption/TranslatableCaption.java @@ -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 * diff --git a/Core/src/main/java/com/plotsquared/core/inject/modules/CommandModule.java b/Core/src/main/java/com/plotsquared/core/inject/modules/CommandModule.java new file mode 100644 index 000000000..53f32008c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/inject/modules/CommandModule.java @@ -0,0 +1,46 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * 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 . + */ +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 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); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java b/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java index 05f3478bc..623c36197 100644 --- a/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java +++ b/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java @@ -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; diff --git a/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java b/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java index b2fdb1441..4ed178e72 100644 --- a/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java +++ b/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java @@ -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; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5af6d937b..07349f019 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,8 @@ paperlib = "1.0.8" informative-annotations = "1.4" vault = "1.7.1" serverlib = "2.3.4" +cloud = "2.0.0-beta.1" +cloudRequirements = "1.0.0-beta.1" # Gradle plugins shadow = "8.1.1" @@ -66,7 +68,7 @@ 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" } @@ -77,6 +79,10 @@ informativeAnnotations = { group = "com.intellectualsites.informative-annotation 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.github.johnrengelman.shadow", version.ref = "shadow" }