diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a002c91d8..2a7a72c51 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: fail-fast: true steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 + - uses: gradle/actions/wrapper-validation@v3 - name: JDK ${{ matrix.java }} uses: actions/setup-java@v4 with: diff --git a/api/src/main/java/net/draycia/carbon/api/channels/ChatChannel.java b/api/src/main/java/net/draycia/carbon/api/channels/ChatChannel.java index 9e0e048ff..226fd8943 100644 --- a/api/src/main/java/net/draycia/carbon/api/channels/ChatChannel.java +++ b/api/src/main/java/net/draycia/carbon/api/channels/ChatChannel.java @@ -124,4 +124,32 @@ public interface ChatChannel extends Keyed, ChatComponentRenderer { */ boolean emptyRadiusRecipientsMessage(); + /** + * The time in milliseconds between player messages. + * -1 and 0 disable the cooldown for this channel. + * + * @return The message cooldown in millis. + * @since 3.0.0 + */ + long cooldown(); + + /** + * The epoch time (millis) when the player's cooldown expires. + * + * @param player The player + * @return The epoch time (millis) when the player's cooldown expires. + * @since 3.0.0 + */ + long playerCooldown(CarbonPlayer player); + + /** + * Starts the cooldown timer for the specified player. Duration will be the channel cooldown. + * Returns the player's old cooldown time, if they have one. + * + * @param player The player + * @return The player's old cooldown, or 0 if they don't have one. + * @since 3.0.0 + */ + long startCooldown(CarbonPlayer player); + } diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 029254ab9..7da44a1d8 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -18,11 +18,6 @@ dependencies { implementation(libs.gremlin.gradle) implementation(libs.run.task) - implementation(libs.pluginYml) - // Implementation dependencies of plugin-yml - implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.1") - // https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) } diff --git a/build-logic/src/main/kotlin/PaperPlugin.kt b/build-logic/src/main/kotlin/PaperPlugin.kt deleted file mode 100644 index 6856c2cc2..000000000 --- a/build-logic/src/main/kotlin/PaperPlugin.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2017 Minecrell - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -import net.minecrell.pluginyml.InvalidPluginDescriptionException -import net.minecrell.pluginyml.PlatformPlugin -import org.gradle.api.Project -import org.gradle.api.artifacts.result.ResolvedComponentResult - -class PaperPlugin : PlatformPlugin("Paper", "paper-plugin.yml") { - - companion object { - @JvmStatic - private val VALID_NAME = Regex("^[A-Za-z0-9 _.-]+$") - } - - override fun createExtension(project: Project) = PaperPluginDescription(project) - - override fun setDefaults(project: Project, description: PaperPluginDescription) { - description.name = description.name ?: project.name - description.version = description.version ?: project.version.toString() - description.description = description.description ?: project.description - description.website = description.website ?: project.findProperty("url")?.toString() - description.author = description.author ?: project.findProperty("author")?.toString() - } - - override fun setLibraries(libraries: ResolvedComponentResult?, description: PaperPluginDescription) { - } - - override fun validate(description: PaperPluginDescription) { - val name = description.name ?: throw InvalidPluginDescriptionException("Plugin name is not set") - if (!VALID_NAME.matches(name)) throw InvalidPluginDescriptionException("Invalid plugin name: should match $VALID_NAME") - - if (description.version.isNullOrEmpty()) throw InvalidPluginDescriptionException("Plugin version is not set") - - val main = description.main ?: throw InvalidPluginDescriptionException("Main class is not defined") - if (main.isEmpty()) throw InvalidPluginDescriptionException("Main class cannot be empty") - if (main.startsWith("org.bukkit.")) throw InvalidPluginDescriptionException("Main may not be within the org.bukkit namespace") - } - -} diff --git a/build-logic/src/main/kotlin/PaperPluginDescription.kt b/build-logic/src/main/kotlin/PaperPluginDescription.kt deleted file mode 100644 index 8bce13d53..000000000 --- a/build-logic/src/main/kotlin/PaperPluginDescription.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2017 Minecrell - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -import com.fasterxml.jackson.databind.PropertyNamingStrategies -import com.fasterxml.jackson.databind.annotation.JsonNaming -import groovy.lang.Closure -import net.minecrell.pluginyml.PluginDescription -import net.minecrell.pluginyml.bukkit.BukkitPluginDescription -import org.gradle.api.NamedDomainObjectContainer -import org.gradle.api.Project -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Nested -import org.gradle.api.tasks.Optional - -@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy::class) -class PaperPluginDescription(project: Project) : PluginDescription { - - @Input - @Optional - var apiVersion: String? = null - @Input - var name: String? = null - @Input - var version: String? = null - @Input - var main: String? = null - @Input - var loader: String? = null - @Input - @Optional - var description: String? = null - @Input - @Optional - var author: String? = null - @Input - @Optional - var authors: List? = null - @Input - @Optional - var website: String? = null - @Input - @Optional - var prefix: String? = null - @Input - @Optional - var defaultPermission: BukkitPluginDescription.Permission.Default? = null - @Input @Optional var foliaSupported: Boolean? = null - @Nested var dependencies: Dependencies = Dependencies() - - fun bootstrapDependency(name: String, load: Load = Load.OMIT, required: Boolean = true, joinClasspath: Boolean = true) { - dependencies.bootstrap[name] = Dependency(load, required, joinClasspath) - } - - fun dependency(name: String, load: Load = Load.OMIT, required: Boolean = true, joinClasspath: Boolean = true) { - dependencies.server[name] = Dependency(load, required, joinClasspath) - } - - enum class Load { - BEFORE, AFTER, OMIT - } - - data class Dependencies( - @Nested - val bootstrap: MutableMap = mutableMapOf(), - @Nested - val server: MutableMap = mutableMapOf() - ) - - @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy::class) - data class Dependency(@Input val load: Load = Load.OMIT, @Input val required: Boolean = true, @Input val joinClasspath: Boolean = true) - - @Nested - val permissions: NamedDomainObjectContainer = project.container(BukkitPluginDescription.Permission::class.java) - - // For Groovy DSL - fun permissions(closure: Closure) = permissions.configure(closure) - -} diff --git a/build-logic/src/main/kotlin/carbon.base-conventions.gradle.kts b/build-logic/src/main/kotlin/carbon.base-conventions.gradle.kts index 846462abb..d4bd576b6 100644 --- a/build-logic/src/main/kotlin/carbon.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/carbon.base-conventions.gradle.kts @@ -33,8 +33,8 @@ indraSpotlessLicenser { tasks { withType { - // disable 'warning: No processor claimed any of these annotations' spam - options.compilerArgs.add("-Xlint:-processing") + // disable unclaimed annotation and missing annotation warnings + options.compilerArgs.add("-Xlint:-processing,-classfile") options.compilerArgs.add("-parameters") } } diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 1477a7f54..3c91af1c6 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -73,7 +73,7 @@ fun Task.standardRelocations() { } fun Task.relocateCloud() { - relocateDependency("cloud.commandframework") + relocateDependency("org.incendo.cloud") } fun Task.relocateGuice() { diff --git a/build-logic/src/main/kotlin/paper-plugin-yml.gradle.kts b/build-logic/src/main/kotlin/paper-plugin-yml.gradle.kts deleted file mode 100644 index f2d92af35..000000000 --- a/build-logic/src/main/kotlin/paper-plugin-yml.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -plugins.apply(PaperPlugin::class) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index deb3b9959..e5dbd2a86 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -17,9 +17,11 @@ dependencies { // Cloud api(platform(libs.cloudBom)) api(libs.cloudCore) + api(platform(libs.cloudMinecraftBom)) api(libs.cloudMinecraftExtras) { isTransitive = false } + api(libs.cloudSigned) // Other compileOnlyApi(libs.guice) { diff --git a/common/src/main/java/net/draycia/carbon/common/CarbonCommonModule.java b/common/src/main/java/net/draycia/carbon/common/CarbonCommonModule.java index 9c9bc75b0..602920b64 100644 --- a/common/src/main/java/net/draycia/carbon/common/CarbonCommonModule.java +++ b/common/src/main/java/net/draycia/carbon/common/CarbonCommonModule.java @@ -40,9 +40,9 @@ import net.draycia.carbon.api.event.CarbonEventHandler; import net.draycia.carbon.api.users.UserManager; import net.draycia.carbon.common.channels.CarbonChannelRegistry; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.ExecutionCoordinatorHolder; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.argument.PlayerSuggestions; import net.draycia.carbon.common.command.commands.ClearChatCommand; import net.draycia.carbon.common.command.commands.ContinueCommand; @@ -86,6 +86,7 @@ import net.draycia.carbon.common.messages.placeholders.ComponentPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.IntPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.KeyPlaceholderResolver; +import net.draycia.carbon.common.messages.placeholders.LongPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.OptionPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.StringPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.UUIDPlaceholderResolver; @@ -166,6 +167,7 @@ public CarbonMessages carbonMessages( final UUIDPlaceholderResolver uuidPlaceholderResolver, final StringPlaceholderResolver stringPlaceholderResolver, final IntPlaceholderResolver intPlaceholderResolver, + final LongPlaceholderResolver longPlaceholderResolver, final KeyPlaceholderResolver keyPlaceholderResolver, final BooleanPlaceholderResolver booleanPlaceholderResolver, final CarbonMessageSource carbonMessageSource, @@ -182,6 +184,7 @@ public CarbonMessages carbonMessages( .weightedPlaceholderResolver(UUID.class, uuidPlaceholderResolver, 0) .weightedPlaceholderResolver(String.class, stringPlaceholderResolver, 0) .weightedPlaceholderResolver(Integer.class, intPlaceholderResolver, 0) + .weightedPlaceholderResolver(Long.class, longPlaceholderResolver, 0) .weightedPlaceholderResolver(Key.class, keyPlaceholderResolver, 0) .weightedPlaceholderResolver(Boolean.class, booleanPlaceholderResolver, 0) .weightedPlaceholderResolver(Option.class, new OptionPlaceholderResolver<>(), 0) @@ -196,7 +199,7 @@ public ExecutionCoordinatorHolder executionCoordinatorHolder(final Logger logger @Override protected void configure() { - this.install(new FactoryModuleBuilder().build(ArgumentFactory.class)); + this.install(new FactoryModuleBuilder().build(ParserFactory.class)); this.install(factoryModule(PacketFactory.class)); this.bind(ServerId.KEY).toInstance(UUID.randomUUID()); this.bind(ChannelRegistry.class).to(CarbonChannelRegistry.class); diff --git a/common/src/main/java/net/draycia/carbon/common/RawChat.java b/common/src/main/java/net/draycia/carbon/common/RawChat.java new file mode 100644 index 000000000..a348917f0 --- /dev/null +++ b/common/src/main/java/net/draycia/carbon/common/RawChat.java @@ -0,0 +1,35 @@ +/* + * CarbonChat + * + * Copyright (c) 2024 Josua Parks (Vicarious) + * 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 net.draycia.carbon.common; + +import com.google.inject.BindingAnnotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Injection binding annotation for the raw chat type key. + */ +@BindingAnnotation +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD}) +public @interface RawChat { +} diff --git a/common/src/main/java/net/draycia/carbon/common/channels/CarbonChannelRegistry.java b/common/src/main/java/net/draycia/carbon/common/channels/CarbonChannelRegistry.java index b147558c8..0776eb1e0 100644 --- a/common/src/main/java/net/draycia/carbon/common/channels/CarbonChannelRegistry.java +++ b/common/src/main/java/net/draycia/carbon/common/channels/CarbonChannelRegistry.java @@ -19,9 +19,6 @@ */ package net.draycia.carbon.common.channels; -import cloud.commandframework.Command; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; @@ -51,6 +48,7 @@ import net.draycia.carbon.api.event.events.ChannelSwitchEvent; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.common.DataDirectory; +import net.draycia.carbon.common.RawChat; import net.draycia.carbon.common.command.Commander; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.config.ConfigManager; @@ -64,17 +62,23 @@ import net.draycia.carbon.common.util.Exceptions; import net.draycia.carbon.common.util.FileUtil; import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.chat.ChatType; import net.kyori.adventure.key.Key; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.minecraft.signed.SignedString; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.loader.ConfigurationLoader; import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import static org.incendo.cloud.minecraft.signed.SignedGreedyStringParser.signedGreedyStringParser; + @Singleton @DefaultQualifier(NonNull.class) public class CarbonChannelRegistry extends ChatListenerInternal implements ChannelRegistry { @@ -86,6 +90,7 @@ public class CarbonChannelRegistry extends ChatListenerInternal implements Chann private @MonotonicNonNull Key defaultKey; private final CarbonMessages carbonMessages; private final CarbonEventHandler eventHandler; + private final Key rawChatKey; private final Map> handlers = new HashMap<>(); private record SpecialHandler(Class cls, Supplier defaultSupplier) {} @@ -110,7 +115,8 @@ public CarbonChannelRegistry( final Logger logger, final ConfigManager config, final CarbonMessages carbonMessages, - final CarbonEventHandler events + final CarbonEventHandler events, + @RawChat final Key rawChatKey ) { super(events, carbonMessages, config); this.configChannelDir = dataDirectory.resolve("channels"); @@ -119,6 +125,7 @@ public CarbonChannelRegistry( this.config = config; this.carbonMessages = carbonMessages; this.eventHandler = events; + this.rawChatKey = rawChatKey; if (config.primaryConfig().partyChat().enabled) { this.registerSpecialConfigChannel(PartyChatChannel.FILE_NAME, PartyChatChannel.class); @@ -326,22 +333,22 @@ private void sendMessageInChannelAsConsole( final ChatChannel channel, final String plainMessage ) { - this.sendMessageInChannel(new ConsoleCarbonPlayer(sender), channel, plainMessage); + this.sendMessageInChannel(new ConsoleCarbonPlayer(sender), channel, SignedString.unsigned(plainMessage)); } private void sendMessageInChannel( final CarbonPlayer sender, final ChatChannel channel, - final String plainMessage + final SignedString message ) { - final @Nullable CarbonChatEventImpl chatEvent = this.prepareAndEmitChatEvent(sender, plainMessage, null, channel); + final @Nullable CarbonChatEventImpl chatEvent = this.prepareAndEmitChatEvent(sender, message.string(), message.signedMessage(), channel); if (chatEvent == null || chatEvent.cancelled()) { return; } for (final Audience recipient : chatEvent.recipients()) { - recipient.sendMessage(chatEvent.renderFor(recipient)); + message.sendMessage(recipient, ChatType.chatType(this.rawChatKey), chatEvent.renderFor(recipient)); } } @@ -354,7 +361,7 @@ private void registerChannelCommands(final ChatChannel channel) { Command.Builder builder = commandManager.commandBuilder(channel.commandName(), channel.commandAliases(), commandManager.createDefaultCommandMeta()) - .argument(StringArgument.builder("message").greedy().asOptional().build()); + .optional("message", signedGreedyStringParser()); if (channel.permission() != null) { builder = builder.permission(channel.permission()); @@ -371,15 +378,15 @@ private void registerChannelCommands(final ChatChannel channel) { final Command command = builder.senderType(Commander.class) .handler(handler -> { - final Commander commander = handler.getSender(); - final @Nullable ChatChannel chatChannel = this.channel(channelKey); + final Commander commander = handler.sender(); + @Nullable ChatChannel chatChannel = this.channel(channelKey); if (!(commander instanceof PlayerCommander playerCommander)) { if (chatChannel != null && handler.contains("message")) { - final String message = handler.get("message"); + final SignedString message = handler.get("message"); // TODO: trigger platform events related to chat - this.sendMessageInChannelAsConsole(commander, chatChannel, message); + this.sendMessageInChannelAsConsole(commander, chatChannel, message.string()); } return; @@ -396,16 +403,20 @@ private void registerChannelCommands(final ChatChannel channel) { this.carbonMessages.channelJoined(player); } if (handler.contains("message")) { - final String message = handler.get("message"); + final SignedString message = handler.get("message"); // TODO: trigger platform events related to chat this.sendMessageInChannel(player, chatChannel, message); } else { + if (this.config.primaryConfig().returnToDefaultChannel() && player.selectedChannel().key().equals(channelKey)) { + chatChannel = this.defaultChannel(); + } + final ChannelSwitchEvent switchEvent = new ChannelSwitchEventImpl(player, chatChannel); this.eventHandler.emit(switchEvent); player.selectedChannel(switchEvent.channel()); - this.carbonMessages.changedChannels(player, channelKey.value()); + this.carbonMessages.changedChannels(player, chatChannel.key().value()); } }) .build(); diff --git a/common/src/main/java/net/draycia/carbon/common/channels/ConfigChatChannel.java b/common/src/main/java/net/draycia/carbon/common/channels/ConfigChatChannel.java index a2ceb4930..13c24a9ee 100644 --- a/common/src/main/java/net/draycia/carbon/common/channels/ConfigChatChannel.java +++ b/common/src/main/java/net/draycia/carbon/common/channels/ConfigChatChannel.java @@ -23,7 +23,9 @@ import io.leangen.geantyref.TypeToken; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.UUID; import net.draycia.carbon.api.CarbonServer; @@ -41,6 +43,7 @@ import net.draycia.carbon.common.messages.placeholders.ComponentPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.IntPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.KeyPlaceholderResolver; +import net.draycia.carbon.common.messages.placeholders.LongPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.StringPlaceholderResolver; import net.draycia.carbon.common.messages.placeholders.UUIDPlaceholderResolver; import net.draycia.carbon.common.util.Exceptions; @@ -111,6 +114,10 @@ public class ConfigChatChannel implements ChatChannel { because they're out of range from the radius.""") private boolean emptyRadiusRecipientsMessage = true; + private Map cooldowns = new HashMap<>(); + + private long cooldown = -1; + @Override public @Nullable String quickPrefix() { if (this.quickPrefix == null || this.quickPrefix.isBlank()) { @@ -185,6 +192,25 @@ public List recipients(final CarbonPlayer sender) { return recipients; } + @Override + public long cooldown() { + return this.cooldown * 1000; // Seconds to millis + } + + @Override + public long playerCooldown(final CarbonPlayer player) { + if (this.cooldown() <= 0) { + return 0; + } + + return Objects.requireNonNullElse(this.cooldowns.get(player.uuid()), 0L); + } + + public long startCooldown(final CarbonPlayer player) { + final long expiresAt = System.currentTimeMillis() + this.cooldown(); + return Objects.requireNonNullElse(this.cooldowns.put(player.uuid(), expiresAt), 0L); + } + @Override public @NonNull Key key() { return Objects.requireNonNull(this.key); @@ -214,6 +240,7 @@ private ConfigChannelMessages loadMessages() { .weightedPlaceholderResolver(UUID.class, uuidPlaceholderResolver, 0) .weightedPlaceholderResolver(String.class, stringPlaceholderResolver, 0) .weightedPlaceholderResolver(Integer.class, new IntPlaceholderResolver<>(), 0) + .weightedPlaceholderResolver(Long.class, new LongPlaceholderResolver<>(), 0) .weightedPlaceholderResolver(Key.class, keyPlaceholderResolver, 0) .weightedPlaceholderResolver(Boolean.class, booleanPlaceholderResolver, 0) .create(this.getClass().getClassLoader()); diff --git a/common/src/main/java/net/draycia/carbon/common/command/ExecutionCoordinatorHolder.java b/common/src/main/java/net/draycia/carbon/common/command/ExecutionCoordinatorHolder.java index 47766ac85..ae2e4361b 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/ExecutionCoordinatorHolder.java +++ b/common/src/main/java/net/draycia/carbon/common/command/ExecutionCoordinatorHolder.java @@ -19,21 +19,18 @@ */ package net.draycia.carbon.common.command; -import cloud.commandframework.CommandTree; -import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator; -import cloud.commandframework.execution.CommandExecutionCoordinator; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import net.draycia.carbon.common.util.ConcurrentUtil; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.execution.ExecutionCoordinator; @DefaultQualifier(NonNull.class) public record ExecutionCoordinatorHolder( - Function, CommandExecutionCoordinator> executionCoordinator, + ExecutionCoordinator executionCoordinator, ExecutorService executorService ) { @@ -44,9 +41,7 @@ public void shutdown() { public static ExecutionCoordinatorHolder create(final Logger logger) { final ExecutorService executorService = Executors.newFixedThreadPool(4, ConcurrentUtil.carbonThreadFactory(logger, "Commands")); return new ExecutionCoordinatorHolder( - AsynchronousCommandExecutionCoordinator.builder() - .withExecutor(executorService) - .build(), + ExecutionCoordinator.coordinatorFor(executorService), executorService ); } diff --git a/common/src/main/java/net/draycia/carbon/common/command/ArgumentFactory.java b/common/src/main/java/net/draycia/carbon/common/command/ParserFactory.java similarity index 85% rename from common/src/main/java/net/draycia/carbon/common/command/ArgumentFactory.java rename to common/src/main/java/net/draycia/carbon/common/command/ParserFactory.java index 76c117134..0df7a7060 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/ArgumentFactory.java +++ b/common/src/main/java/net/draycia/carbon/common/command/ParserFactory.java @@ -19,13 +19,13 @@ */ package net.draycia.carbon.common.command; -import net.draycia.carbon.common.command.argument.CarbonPlayerArgument; +import net.draycia.carbon.common.command.argument.CarbonPlayerParser; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; @DefaultQualifier(NonNull.class) -public interface ArgumentFactory { +public interface ParserFactory { - CarbonPlayerArgument.Builder carbonPlayer(String name); + CarbonPlayerParser carbonPlayer(); } diff --git a/common/src/main/java/net/draycia/carbon/common/command/argument/CarbonPlayerArgument.java b/common/src/main/java/net/draycia/carbon/common/command/argument/CarbonPlayerArgument.java deleted file mode 100644 index fe3120c77..000000000 --- a/common/src/main/java/net/draycia/carbon/common/command/argument/CarbonPlayerArgument.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * CarbonChat - * - * Copyright (c) 2024 Josua Parks (Vicarious) - * 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 net.draycia.carbon.common.command.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.keys.CloudKey; -import cloud.commandframework.keys.SimpleCloudKey; -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import com.google.inject.assistedinject.AssistedInject; -import io.leangen.geantyref.TypeToken; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -import net.draycia.carbon.api.users.CarbonPlayer; -import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.Commander; -import net.draycia.carbon.common.command.exception.ComponentException; -import net.draycia.carbon.common.messages.CarbonMessages; -import net.draycia.carbon.common.users.ProfileResolver; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; - -@DefaultQualifier(NonNull.class) -public final class CarbonPlayerArgument extends CommandArgument { - - private CarbonPlayerArgument( - final boolean required, - final String name, - final String defaultValue, - final @Nullable BiFunction, String, - List> suggestionsProvider, - final ArgumentDescription defaultDescription, - final Parser parser - ) { - super(required, name, parser, defaultValue, CarbonPlayer.class, suggestionsProvider, defaultDescription); - } - - public static final class Builder extends CommandArgument.TypedBuilder { - - private final Parser parser; - - @AssistedInject - private Builder(final @Assisted String name, final Parser parser) { - super(CarbonPlayer.class, name); - this.parser = parser; - } - - @Override - public CarbonPlayerArgument build() { - return new CarbonPlayerArgument( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription(), - this.parser - ); - } - - } - - public static final class Parser implements ArgumentParser { - - // This hack only works properly when there is 0 or 1 CarbonPlayerArguments in a chain, since we don't use the arg name - public static CloudKey INPUT_STRING = SimpleCloudKey.of(Parser.class.getSimpleName() + "-input", TypeToken.get(String.class)); - - private final PlayerSuggestions suggestions; - private final UserManager userManager; - private final ProfileResolver profileResolver; - private final CarbonMessages messages; - - @Inject - private Parser( - final PlayerSuggestions suggestions, - final UserManager userManager, - final ProfileResolver profileResolver, - final CarbonMessages messages - ) { - this.suggestions = suggestions; - this.userManager = userManager; - this.profileResolver = profileResolver; - this.messages = messages; - } - - @Override - public ArgumentParseResult parse( - final CommandContext commandContext, - final Queue inputQueue - ) { - final String input = inputQueue.peek(); - - final @Nullable CarbonPlayer join = this.profileResolver.resolveUUID(input, commandContext.isSuggestions()).thenCompose(uuid -> { - if (uuid == null) { - return CompletableFuture.completedFuture(null); - } - return this.userManager.user(uuid); - }).join(); - - if (join == null) { - return ArgumentParseResult.failure(new ParseException(input, this.messages)); - } - - commandContext.store(INPUT_STRING, input); - inputQueue.remove(); - return ArgumentParseResult.success(join); - } - - @Override - public List suggestions( - final CommandContext commandContext, - final String input - ) { - return this.suggestions.apply(commandContext, input); - } - - } - - public static final class ParseException extends ComponentException { - - private static final long serialVersionUID = -8331761537951077684L; - private final String input; - - public ParseException(final String input, final CarbonMessages messages) { - super(messages.errorCommandInvalidPlayer(input)); - this.input = input; - } - - public String input() { - return this.input; - } - - } - -} diff --git a/common/src/main/java/net/draycia/carbon/common/command/argument/CarbonPlayerParser.java b/common/src/main/java/net/draycia/carbon/common/command/argument/CarbonPlayerParser.java new file mode 100644 index 000000000..570b33321 --- /dev/null +++ b/common/src/main/java/net/draycia/carbon/common/command/argument/CarbonPlayerParser.java @@ -0,0 +1,106 @@ +/* + * CarbonChat + * + * Copyright (c) 2024 Josua Parks (Vicarious) + * 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 net.draycia.carbon.common.command.argument; + +import com.google.inject.Inject; +import io.leangen.geantyref.TypeToken; +import java.util.concurrent.CompletableFuture; +import net.draycia.carbon.api.users.CarbonPlayer; +import net.draycia.carbon.api.users.UserManager; +import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.exception.ComponentException; +import net.draycia.carbon.common.messages.CarbonMessages; +import net.draycia.carbon.common.users.ProfileResolver; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.ArgumentParseResult; +import org.incendo.cloud.parser.ArgumentParser; +import org.incendo.cloud.parser.ParserDescriptor; +import org.incendo.cloud.suggestion.SuggestionProvider; + +@DefaultQualifier(NonNull.class) +public final class CarbonPlayerParser implements ArgumentParser.FutureArgumentParser, ParserDescriptor { + + private final PlayerSuggestions suggestions; + private final UserManager userManager; + private final ProfileResolver profileResolver; + private final CarbonMessages messages; + + @Inject + private CarbonPlayerParser( + final PlayerSuggestions suggestions, + final UserManager userManager, + final ProfileResolver profileResolver, + final CarbonMessages messages + ) { + this.suggestions = suggestions; + this.userManager = userManager; + this.profileResolver = profileResolver; + this.messages = messages; + } + + @Override + public CompletableFuture> parseFuture( + final CommandContext commandContext, + final CommandInput commandInput + ) { + final String input = commandInput.readString(); + return this.profileResolver.resolveUUID(input, commandContext.isSuggestions()).thenCompose(uuid -> { + if (uuid == null) { + return ArgumentParseResult.failureFuture(new ParseException(input, this.messages)); + } + return this.userManager.user(uuid).thenApply(ArgumentParseResult::success); + }); + } + + @Override + public @NonNull SuggestionProvider suggestionProvider() { + return this.suggestions; + } + + @Override + public @NonNull TypeToken valueType() { + return TypeToken.get(CarbonPlayer.class); + } + + @Override + public @NonNull ArgumentParser parser() { + return this; + } + + public static final class ParseException extends ComponentException { + + private static final long serialVersionUID = -8331761537951077684L; + private final String input; + + public ParseException(final String input, final CarbonMessages messages) { + super(messages.errorCommandInvalidPlayer(input)); + this.input = input; + } + + public String input() { + return this.input; + } + + } + +} diff --git a/common/src/main/java/net/draycia/carbon/common/command/argument/PlayerSuggestions.java b/common/src/main/java/net/draycia/carbon/common/command/argument/PlayerSuggestions.java index 9d4a58786..269ed377e 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/argument/PlayerSuggestions.java +++ b/common/src/main/java/net/draycia/carbon/common/command/argument/PlayerSuggestions.java @@ -19,13 +19,11 @@ */ package net.draycia.carbon.common.command.argument; -import cloud.commandframework.context.CommandContext; -import java.util.List; -import java.util.function.BiFunction; import net.draycia.carbon.common.command.Commander; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.suggestion.SuggestionProvider; @DefaultQualifier(NonNull.class) -public interface PlayerSuggestions extends BiFunction, String, List> { +public interface PlayerSuggestions extends SuggestionProvider { } diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/ClearChatCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/ClearChatCommand.java index 326a1fc29..785dd7e85 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/ClearChatCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/ClearChatCommand.java @@ -19,8 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; import com.google.inject.Inject; import net.draycia.carbon.api.CarbonServer; import net.draycia.carbon.common.command.CarbonCommand; @@ -33,6 +31,9 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; @DefaultQualifier(NonNull.class) public final class ClearChatCommand extends CarbonCommand { @@ -69,8 +70,7 @@ public Key key() { public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) .permission("carbon.clearchat.clear") - .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandClearChatDescription()) + .commandDescription(richDescription(this.carbonMessages.commandClearChatDescription())) .handler(handler -> { // Not fond of having to send 50 messages to each player // Are we not able to just paste in 50 newlines and call it a day? @@ -85,7 +85,7 @@ public void init() { final Component senderName; final String username; - if (handler.getSender() instanceof PlayerCommander player) { + if (handler.sender() instanceof PlayerCommander player) { senderName = player.carbonPlayer().displayName(); username = player.carbonPlayer().username(); } else { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/ContinueCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/ContinueCommand.java index f8b26d051..8cf46bdcc 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/ContinueCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/ContinueCommand.java @@ -19,10 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import java.util.UUID; import net.draycia.carbon.api.users.CarbonPlayer; @@ -37,6 +33,11 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.minecraft.signed.SignedString; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.minecraft.signed.SignedGreedyStringParser.signedGreedyStringParser; @DefaultQualifier(NonNull.class) public final class ContinueCommand extends CarbonCommand { @@ -72,20 +73,19 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(StringArgument.greedy("message"), - RichDescription.of(this.messages.commandContinueArgumentMessage())) + .required("message", signedGreedyStringParser(), richDescription(this.messages.commandContinueArgumentMessage())) .permission("carbon.whisper.continue") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.commandContinueDescription()) + .commandDescription(richDescription(this.messages.commandContinueDescription())) .handler(ctx -> { - final CarbonPlayer sender = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + final CarbonPlayer sender = ctx.sender().carbonPlayer(); if (sender.muted()) { this.messages.muteCannotSpeak(sender); return; } - final String message = ctx.get("message"); + final SignedString message = ctx.get("message"); final @Nullable UUID whisperTarget = sender.lastWhisperTarget(); if (whisperTarget == null) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/DebugCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/DebugCommand.java index 46e655605..911b4cafe 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/DebugCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/DebugCommand.java @@ -19,16 +19,13 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import java.util.ArrayList; import net.draycia.carbon.api.users.CarbonPlayer; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; @@ -37,23 +34,26 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; @DefaultQualifier(NonNull.class) public final class DebugCommand extends CarbonCommand { private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; @Inject public DebugCommand( final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory + final ParserFactory parserFactory ) { this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; } @Override @@ -69,13 +69,13 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.carbonMessages.commandDebugArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), + richDescription(this.carbonMessages.commandDebugArgumentPlayer())) .permission("carbon.debug") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandDebugDescription()) + .commandDescription(richDescription(this.carbonMessages.commandDebugDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/HelpCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/HelpCommand.java index 98bb3f56b..90a8da2d1 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/HelpCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/HelpCommand.java @@ -19,15 +19,9 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandHelpHandler; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.minecraft.extras.AudienceProvider; -import cloud.commandframework.minecraft.extras.MinecraftHelp; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; -import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; @@ -35,16 +29,26 @@ import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.help.result.CommandEntry; +import org.incendo.cloud.minecraft.extras.AudienceProvider; +import org.incendo.cloud.minecraft.extras.MinecraftHelp; +import org.incendo.cloud.suggestion.Suggestion; +import org.intellij.lang.annotations.Subst; -import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY; import static net.kyori.adventure.text.format.NamedTextColor.GRAY; import static net.kyori.adventure.text.format.NamedTextColor.WHITE; import static net.kyori.adventure.text.format.TextColor.color; +import static org.incendo.cloud.minecraft.extras.MinecraftHelp.helpColors; +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser; @DefaultQualifier(NonNull.class) public final class HelpCommand extends CarbonCommand { @@ -77,12 +81,10 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .literal("help", - RichDescription.of(this.carbonMessages.commandHelpDescription())) - .argument(StringArgument.builder("query") - .greedy().withSuggestionsProvider(this::suggestQueries).asOptional(), - RichDescription.of(this.carbonMessages.commandHelpArgumentQuery())) + .literal("help") + .optional("query", greedyStringParser(), richDescription(this.carbonMessages.commandHelpArgumentQuery()), this::suggestQueries) .permission("carbon.help") + .commandDescription(richDescription(this.carbonMessages.commandHelpDescription())) .handler(this::execute) .build(); @@ -90,50 +92,41 @@ public void init() { } private void execute(final CommandContext ctx) { - this.minecraftHelp.queryCommands(ctx.getOrDefault("query", ""), ctx.getSender()); + this.minecraftHelp.queryCommands(ctx.getOrDefault("query", ""), ctx.sender()); } - private List suggestQueries(final CommandContext ctx, final String input) { - final var topic = this.commandManager.createCommandHelpHandler().queryRootIndex(ctx.getSender()); - return topic.getEntries().stream().map(CommandHelpHandler.VerboseHelpEntry::getSyntaxString).toList(); + private CompletableFuture> suggestQueries(final CommandContext ctx, final CommandInput input) { + final var result = this.commandManager.createHelpHandler().queryRootIndex(ctx.sender()); + return CompletableFuture.completedFuture(result.entries().stream().map(CommandEntry::syntax).map(Suggestion::suggestion).toList()); } private static MinecraftHelp createHelp( final CommandManager manager, final CarbonMessageSource messageSource ) { - final MinecraftHelp help = new MinecraftHelp<>( - "/carbon help", - AudienceProvider.nativeAudience(), - manager - ); - - help.setHelpColors( - MinecraftHelp.HelpColors.of( + return MinecraftHelp.builder() + .commandManager(manager) + .audienceProvider(AudienceProvider.nativeAudience()) + .commandPrefix("/carbon help") + .colors(helpColors( color(0xE099FF), WHITE, color(0xDD1BC4), GRAY, DARK_GRAY - ) - ); - - help.messageProvider((sender, key, args) -> { - final String messageKey = "command.help.misc." + key; - final TagResolver.Builder tagResolver = TagResolver.builder(); - - // Total hack but works for now - if (args.length == 2) { - tagResolver - .tag("page", Tag.selfClosingInserting(text(args[0]))) - .tag("max_pages", Tag.selfClosingInserting(text(args[1])) - ); - } - - return MiniMessage.miniMessage().deserialize(messageSource.messageOf(sender, messageKey), tagResolver.build()); - }); - - return help; + )) + .messageProvider((sender, key, args) -> { + final String messageKey = "command.help.misc." + key; + final TagResolver.Builder tagResolver = TagResolver.builder(); + + for (final Map.Entry entry : args.entrySet()) { + @Subst("key") final String k = entry.getKey(); + tagResolver.resolver(Placeholder.parsed(k, entry.getValue())); + } + + return MiniMessage.miniMessage().deserialize(messageSource.messageOf(sender, messageKey), tagResolver.build()); + }) + .build(); } } diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreCommand.java index ec3424ce7..f10edbba7 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreCommand.java @@ -19,22 +19,22 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.UUIDArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.UUIDParser.uuidParser; @DefaultQualifier(NonNull.class) public final class IgnoreCommand extends CarbonCommand { @@ -42,19 +42,19 @@ public final class IgnoreCommand extends CarbonCommand { private final UserManager users; private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; @Inject public IgnoreCommand( final UserManager userManager, final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory + final ParserFactory parserFactory ) { this.users = userManager; this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; } @Override @@ -70,18 +70,17 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.carbonMessages.commandIgnoreArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), richDescription(this.carbonMessages.commandIgnoreArgumentPlayer())) .flag(this.commandManager.flagBuilder("uuid") .withAliases("u") - .withDescription(RichDescription.of(this.carbonMessages.commandIgnoreArgumentUUID())) - .withArgument(UUIDArgument.optional("uuid")) + .withDescription(richDescription(this.carbonMessages.commandIgnoreArgumentUUID())) + .withComponent(uuidParser()) ) .permission("carbon.ignore") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandIgnoreDescription()) + .commandDescription(richDescription(this.carbonMessages.commandIgnoreDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreListCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreListCommand.java index 8b78563b8..cd417fd2d 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreListCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/IgnoreListCommand.java @@ -19,10 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.IntegerArgument; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; import com.google.inject.Inject; import java.util.function.Supplier; import net.draycia.carbon.api.users.CarbonPlayer; @@ -37,6 +33,12 @@ import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.component.DefaultValue; +import org.incendo.cloud.context.CommandContext; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.IntegerParser.integerParser; @DefaultQualifier(NonNull.class) public final class IgnoreListCommand extends CarbonCommand { @@ -74,16 +76,16 @@ public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) .permission("carbon.ignore") .senderType(PlayerCommander.class) - .argument(IntegerArgument.builder("page").withMin(1).asOptionalWithDefault(1)) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.commandIgnoreListDescription()) + .optional("page", integerParser(1), DefaultValue.constant(1)) + .commandDescription(richDescription(this.messages.commandIgnoreListDescription())) .handler(this::execute) .build(); this.commandManager.command(command); } - private void execute(final CommandContext ctx) { - final CarbonPlayer sender = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + private void execute(final CommandContext ctx) { + final CarbonPlayer sender = ctx.sender().carbonPlayer(); final var elements = sender.ignoring().stream() .sorted() // this way page numbers make sense .map(id -> (Supplier) () -> this.users.user(id).join()) diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/JoinCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/JoinCommand.java index c4dea8400..a1037deef 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/JoinCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/JoinCommand.java @@ -19,10 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.channels.ChannelPermissionResult; import net.draycia.carbon.api.channels.ChatChannel; @@ -37,6 +33,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser; @DefaultQualifier(NonNull.class) public final class JoinCommand extends CarbonCommand { @@ -69,21 +71,23 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(StringArgument.builder("channel").greedy().withSuggestionsProvider((context, s) -> { - final CarbonPlayer sender = ((PlayerCommander) context.getSender()).carbonPlayer(); - return sender.leftChannels().stream().map(Key::value).toList(); - }), RichDescription.of(this.carbonMessages.commandJoinDescription())) + .required("channel", greedyStringParser(), SuggestionProvider.blocking( + (context, s) -> { + final CarbonPlayer sender = ((PlayerCommander) context.sender()).carbonPlayer(); + return sender.leftChannels().stream().map(Key::value).map(Suggestion::suggestion).toList(); + } + )) .permission("carbon.join") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandJoinDescription()) + .commandDescription(richDescription(this.carbonMessages.commandJoinDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final @Nullable ChatChannel channel = this.channelRegistry.channelByValue(handler.get("channel")); if (channel == null) { this.carbonMessages.channelNotFound(sender); return; } - final ChannelPermissionResult permitted = channel.speechPermitted(sender); + final ChannelPermissionResult permitted = channel.hearingPermitted(sender); if (!permitted.permitted()) { sender.sendMessage(permitted.reason()); return; diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/LeaveCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/LeaveCommand.java index d61b81df5..2cfee19aa 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/LeaveCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/LeaveCommand.java @@ -19,10 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.channels.ChannelPermissionResult; import net.draycia.carbon.api.channels.ChatChannel; @@ -37,6 +33,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser; @DefaultQualifier(NonNull.class) public final class LeaveCommand extends CarbonCommand { @@ -69,19 +71,20 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(StringArgument.builder("channel").greedy().withSuggestionsProvider((context, s) -> { - final CarbonPlayer sender = ((PlayerCommander) context.getSender()).carbonPlayer(); + .required("channel", greedyStringParser(), SuggestionProvider.blocking((context, s) -> { + final CarbonPlayer sender = ((PlayerCommander) context.sender()).carbonPlayer(); return this.channelRegistry.keys().stream() .map(this.channelRegistry::channel) .filter(x -> !sender.leftChannels().contains(x.key()) && x.speechPermitted(sender).permitted()) .map(x -> x.key().value()) + .map(Suggestion::suggestion) .toList(); - }), RichDescription.of(this.carbonMessages.commandLeaveDescription())) + })) .permission("carbon.join") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandLeaveDescription()) + .commandDescription(richDescription(this.carbonMessages.commandLeaveDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final @Nullable ChatChannel channel = this.channelRegistry.channelByValue(handler.get("channel")); if (channel == null) { this.carbonMessages.channelNotFound(sender); diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/MuteCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/MuteCommand.java index 6b5748838..94d04dd09 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/MuteCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/MuteCommand.java @@ -19,23 +19,23 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.UUIDArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.CarbonServer; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.UUIDParser.uuidParser; @DefaultQualifier(NonNull.class) public final class MuteCommand extends CarbonCommand { @@ -44,7 +44,7 @@ public final class MuteCommand extends CarbonCommand { private final UserManager users; private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; @Inject public MuteCommand( @@ -52,13 +52,13 @@ public MuteCommand( final CarbonServer server, final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory + final ParserFactory parserFactory ) { this.server = server; this.users = userManager; this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; } @Override @@ -74,18 +74,18 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.carbonMessages.commandMuteArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), + richDescription(this.carbonMessages.commandMuteArgumentPlayer())) .flag(this.commandManager.flagBuilder("uuid") .withAliases("u") - .withDescription(RichDescription.of(this.carbonMessages.commandMuteArgumentUUID())) - .withArgument(UUIDArgument.optional("uuid")) + .withDescription(richDescription(this.carbonMessages.commandMuteArgumentUUID())) + .withComponent(uuidParser()) ) .permission("carbon.mute") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandMuteDescription()) + .commandDescription(richDescription(this.carbonMessages.commandMuteDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/MuteInfoCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/MuteInfoCommand.java index 6f68e240c..3b214f248 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/MuteInfoCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/MuteInfoCommand.java @@ -19,22 +19,22 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.UUIDArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.UUIDParser.uuidParser; @DefaultQualifier(NonNull.class) public final class MuteInfoCommand extends CarbonCommand { @@ -42,19 +42,19 @@ public final class MuteInfoCommand extends CarbonCommand { private final UserManager users; private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; @Inject public MuteInfoCommand( final UserManager userManager, final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory + final ParserFactory parserFactory ) { this.users = userManager; this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; } @Override @@ -70,18 +70,17 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.carbonMessages.commandMuteInfoArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), richDescription(this.carbonMessages.commandMuteInfoArgumentPlayer())) .flag(this.commandManager.flagBuilder("uuid") .withAliases("u") - .withDescription(RichDescription.of(this.carbonMessages.commandMuteInfoArgumentUUID())) - .withArgument(UUIDArgument.optional("uuid")) + .withDescription(richDescription(this.carbonMessages.commandMuteInfoArgumentUUID())) + .withComponent(uuidParser()) ) .permission("carbon.mute.info") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandMuteInfoDescription()) + .commandDescription(richDescription(this.carbonMessages.commandMuteInfoDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/NicknameCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/NicknameCommand.java index ca5b8c707..4c998f451 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/NicknameCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/NicknameCommand.java @@ -19,16 +19,12 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.users.CarbonPlayer; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.config.ConfigManager; import net.draycia.carbon.common.messages.CarbonMessages; @@ -40,25 +36,29 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser; @DefaultQualifier(NonNull.class) public final class NicknameCommand extends CarbonCommand { private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; private final ConfigManager config; @Inject public NicknameCommand( final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory, + final ParserFactory parserFactory, final ConfigManager config ) { this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; this.config = config; } @@ -81,35 +81,35 @@ public void init() { // TODO: Allow UUID input for target player final var selfRoot = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()); final var othersRoot = selfRoot.literal("player") - .argument(this.argumentFactory.carbonPlayer("player"), RichDescription.of(this.carbonMessages.commandNicknameArgumentPlayer())); + .required("player", this.parserFactory.carbonPlayer(), richDescription(this.carbonMessages.commandNicknameArgumentPlayer())); // Check nickname this.commandManager.command(selfRoot.permission("carbon.nickname") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandNicknameDescription()) - .handler(ctx -> this.checkOwnNickname(CloudUtils.nonPlayerMustProvidePlayer(this.carbonMessages, ctx.getSender())))); + .commandDescription(richDescription(this.carbonMessages.commandNicknameDescription())) + .handler(ctx -> this.checkOwnNickname(CloudUtils.nonPlayerMustProvidePlayer(this.carbonMessages, ctx.sender())))); this.commandManager.command(othersRoot.permission("carbon.nickname.others") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandNicknameOthersDescription()) - .handler(ctx -> this.checkOthersNickname(ctx.getSender(), ctx.get("player")))); + .commandDescription(richDescription(this.carbonMessages.commandNicknameOthersDescription())) + .handler(ctx -> this.checkOthersNickname(ctx.sender(), ctx.get("player")))); // Set nickname this.commandManager.command(selfRoot.permission("carbon.nickname.set") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandNicknameSetDescription()) - .argument(StringArgument.greedy("nickname"), RichDescription.of(this.carbonMessages.commandNicknameArgumentNickname())) - .handler(ctx -> this.applyNickname(ctx.getSender(), CloudUtils.nonPlayerMustProvidePlayer(this.carbonMessages, ctx.getSender()), ctx.get("nickname")))); + .commandDescription(richDescription(this.carbonMessages.commandNicknameSetDescription())) + .required("nickname", greedyStringParser(), richDescription(this.carbonMessages.commandNicknameArgumentNickname())) + .handler(ctx -> this.applyNickname(ctx.sender(), CloudUtils.nonPlayerMustProvidePlayer(this.carbonMessages, ctx.sender()), ctx.get("nickname")))); this.commandManager.command(othersRoot.permission("carbon.nickname.others.set") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandNicknameOthersSetDescription()) - .argument(StringArgument.greedy("nickname"), RichDescription.of(this.carbonMessages.commandNicknameArgumentNickname())) - .handler(ctx -> this.applyNickname(ctx.getSender(), ctx.get("player"), ctx.get("nickname")))); + .commandDescription(richDescription(this.carbonMessages.commandNicknameOthersSetDescription())) + .required("nickname", greedyStringParser(), richDescription(this.carbonMessages.commandNicknameArgumentNickname())) + .handler(ctx -> this.applyNickname(ctx.sender(), ctx.get("player"), ctx.get("nickname")))); // Reset/remove nickname this.commandManager.command(selfRoot.permission("carbon.nickname.set") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandNicknameResetDescription()) + .commandDescription(richDescription(this.carbonMessages.commandNicknameResetDescription())) .literal("reset") - .handler(ctx -> this.resetNickname(ctx.getSender(), CloudUtils.nonPlayerMustProvidePlayer(this.carbonMessages, ctx.getSender())))); + .handler(ctx -> this.resetNickname(ctx.sender(), CloudUtils.nonPlayerMustProvidePlayer(this.carbonMessages, ctx.sender())))); this.commandManager.command(othersRoot.permission("carbon.nickname.others.set") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandNicknameOthersResetDescription()) + .commandDescription(richDescription(this.carbonMessages.commandNicknameOthersResetDescription())) .literal("reset") - .handler(ctx -> this.resetNickname(ctx.getSender(), ctx.get("player")))); + .handler(ctx -> this.resetNickname(ctx.sender(), ctx.get("player")))); } private void resetNickname(final Commander sender, final CarbonPlayer target) { @@ -141,6 +141,11 @@ private void applyNickname(final Commander sender, final CarbonPlayer target, fi return; } + if (!sender.hasPermission("carbon.nickname.filter") && !plainNick.matches(this.config.primaryConfig().nickname().filter())) { + this.carbonMessages.nicknameErrorFilter(sender, parsedNick); + return; + } + target.nickname(parsedNick); if (sender instanceof PlayerCommander playerCommander diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/PartyCommands.java b/common/src/main/java/net/draycia/carbon/common/command/commands/PartyCommands.java index 3fb56f6d3..dd51150f5 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/PartyCommands.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/PartyCommands.java @@ -19,11 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.IntegerArgument; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; import com.github.benmanes.caffeine.cache.Cache; import com.google.inject.Inject; import java.util.Comparator; @@ -33,10 +28,10 @@ import java.util.function.Supplier; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.Party; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.config.ConfigManager; import net.draycia.carbon.common.messages.CarbonMessages; @@ -52,12 +47,19 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.component.DefaultValue; +import org.incendo.cloud.context.CommandContext; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.IntegerParser.integerParser; +import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser; @DefaultQualifier(NonNull.class) public final class PartyCommands extends CarbonCommand { private final CommandManager commandManager; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; private final UserManagerInternal userManager; private final PartyInvites partyInvites; private final ConfigManager config; @@ -68,7 +70,7 @@ public final class PartyCommands extends CarbonCommand { @Inject public PartyCommands( final CommandManager commandManager, - final ArgumentFactory argumentFactory, + final ParserFactory parserFactory, final UserManagerInternal userManager, final PartyInvites partyInvites, final ConfigManager config, @@ -77,7 +79,7 @@ public PartyCommands( final NetworkUsers network ) { this.commandManager = commandManager; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; this.userManager = userManager; this.partyInvites = partyInvites; this.config = config; @@ -95,36 +97,37 @@ public void init() { final var root = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) .senderType(PlayerCommander.class) .permission("carbon.parties"); - final var info = root.meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.partyDesc()).handler(this::info); + final var info = root.commandDescription(richDescription(this.messages.partyDesc())).handler(this::info); + this.commandManager.command(info); this.commandManager.command(info.literal("page") - .argument(IntegerArgument.builder("page").withMin(1).asOptionalWithDefault(1))); + .optional("page", integerParser(1), DefaultValue.constant(1))); this.commandManager.command( root.literal("create") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.partyCreateDesc()) - .argument(StringArgument.builder("name").greedy().asOptional()) + .commandDescription(richDescription(this.messages.partyCreateDesc())) + .optional("name", greedyStringParser()) .handler(this::createParty) ); this.commandManager.command( root.literal("invite") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.partyInviteDesc()) - .argument(this.argumentFactory.carbonPlayer("player")) + .commandDescription(richDescription(this.messages.partyInviteDesc())) + .required("player", this.parserFactory.carbonPlayer()) .handler(this::invitePlayer) ); this.commandManager.command( root.literal("accept") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.partyAcceptDesc()) - .argument(this.argumentFactory.carbonPlayer("sender").asOptional()) + .commandDescription(richDescription(this.messages.partyAcceptDesc())) + .optional("sender", this.parserFactory.carbonPlayer()) .handler(this::acceptInvite) ); this.commandManager.command( root.literal("leave") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.partyLeaveDesc()) + .commandDescription(richDescription(this.messages.partyLeaveDesc())) .handler(this::leaveParty) ); this.commandManager.command( root.literal("disband") - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.partyDisbandDesc()) + .commandDescription(richDescription(this.messages.partyDisbandDesc())) .handler(this::disbandParty) ); } @@ -139,8 +142,8 @@ public Key key() { return Key.key("carbon", "party"); } - private void info(final CommandContext ctx) { - final CarbonPlayer player = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + private void info(final CommandContext ctx) { + final CarbonPlayer player = ctx.sender().carbonPlayer(); final @Nullable Party party = player.party().join(); if (party == null) { this.messages.notInParty(player); @@ -173,8 +176,8 @@ private void info(final CommandContext ctx) { pagination.render(elements, page, 6).forEach(player::sendMessage); } - private void createParty(final CommandContext ctx) { - final CarbonPlayer player = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + private void createParty(final CommandContext ctx) { + final CarbonPlayer player = ctx.sender().carbonPlayer(); final @Nullable Party oldParty = player.party().join(); if (oldParty != null) { this.messages.mustLeavePartyFirst(player); @@ -193,8 +196,8 @@ private void createParty(final CommandContext ctx) { this.messages.partyCreated(player, party.name()); } - private void invitePlayer(final CommandContext ctx) { - final CarbonPlayer player = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + private void invitePlayer(final CommandContext ctx) { + final CarbonPlayer player = ctx.sender().carbonPlayer(); final CarbonPlayer recipient = ctx.get("player"); if (recipient.uuid().equals(player.uuid())) { this.messages.cannotInviteSelf(player); @@ -215,9 +218,9 @@ private void invitePlayer(final CommandContext ctx) { this.messages.sentPartyInvite(player, recipient.displayName(), party.name()); } - private void acceptInvite(final CommandContext ctx) { + private void acceptInvite(final CommandContext ctx) { final @Nullable CarbonPlayer sender = ctx.getOrDefault("sender", null); - final CarbonPlayer player = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + final CarbonPlayer player = ctx.sender().carbonPlayer(); final @Nullable Invite invite = this.findInvite(player, sender); if (invite == null) { return; @@ -232,8 +235,8 @@ private void acceptInvite(final CommandContext ctx) { this.messages.joinedParty(player, invite.party().name()); } - private void leaveParty(final CommandContext ctx) { - final CarbonPlayer player = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + private void leaveParty(final CommandContext ctx) { + final CarbonPlayer player = ctx.sender().carbonPlayer(); final @Nullable Party old = player.party().join(); if (old == null) { this.messages.mustBeInParty(player); @@ -247,8 +250,8 @@ private void leaveParty(final CommandContext ctx) { this.messages.leftParty(player, old.name()); } - private void disbandParty(final CommandContext ctx) { - final CarbonPlayer player = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + private void disbandParty(final CommandContext ctx) { + final CarbonPlayer player = ctx.sender().carbonPlayer(); final @Nullable Party old = player.party().join(); if (old == null) { this.messages.mustBeInParty(player); diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/ReloadCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/ReloadCommand.java index 5cea9dddf..dea50175d 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/ReloadCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/ReloadCommand.java @@ -19,8 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; import com.google.inject.Inject; import net.draycia.carbon.api.event.CarbonEventHandler; import net.draycia.carbon.common.command.CarbonCommand; @@ -31,6 +29,9 @@ import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; @DefaultQualifier(NonNull.class) public final class ReloadCommand extends CarbonCommand { @@ -66,11 +67,11 @@ public void init() { .literal("reload") .permission("carbon.reload") .senderType(Commander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandReloadDescription()) + .commandDescription(richDescription(this.carbonMessages.commandReloadDescription())) .handler(handler -> { // TODO: Check if all listeners succeeded this.events.emit(new CarbonReloadEvent()); - this.carbonMessages.configReloaded(handler.getSender()); + this.carbonMessages.configReloaded(handler.sender()); }) .build(); diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/ReplyCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/ReplyCommand.java index 2fb0f5bbe..090df6514 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/ReplyCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/ReplyCommand.java @@ -19,10 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import java.util.UUID; import net.draycia.carbon.api.users.CarbonPlayer; @@ -37,6 +33,11 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.minecraft.signed.SignedString; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.minecraft.signed.SignedGreedyStringParser.signedGreedyStringParser; @DefaultQualifier(NonNull.class) public final class ReplyCommand extends CarbonCommand { @@ -72,20 +73,19 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(StringArgument.greedy("message"), - RichDescription.of(this.messages.commandReplyArgumentMessage())) + .required("message", signedGreedyStringParser(), richDescription(this.messages.commandReplyArgumentMessage())) .permission("carbon.whisper.reply") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messages.commandReplyDescription()) + .commandDescription(richDescription(this.messages.commandReplyDescription())) .handler(ctx -> { - final CarbonPlayer sender = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + final CarbonPlayer sender = ctx.sender().carbonPlayer(); if (sender.muted()) { this.messages.muteCannotSpeak(sender); return; } - final String message = ctx.get("message"); + final SignedString message = ctx.get("message"); final @Nullable UUID replyTarget = sender.whisperReplyTarget(); if (replyTarget == null) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/ToggleMessagesCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/ToggleMessagesCommand.java index 62ba86bba..4b1928a9e 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/ToggleMessagesCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/ToggleMessagesCommand.java @@ -19,8 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; import com.google.inject.Inject; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.common.command.CarbonCommand; @@ -29,6 +27,9 @@ import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; public class ToggleMessagesCommand extends CarbonCommand { @@ -59,9 +60,9 @@ public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) .permission("carbon.togglemsg") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandToggleMsgDescription()) + .commandDescription(richDescription(this.carbonMessages.commandToggleMsgDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final boolean nowIgnoring = !sender.ignoringDirectMessages(); sender.ignoringDirectMessages(nowIgnoring); @@ -79,9 +80,9 @@ public void init() { .permission("carbon.togglemsg") .literal("on", "allow") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandToggleMsgDescription()) + .commandDescription(richDescription(this.carbonMessages.commandToggleMsgDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); sender.ignoringDirectMessages(false); this.carbonMessages.whispersToggledOn(sender); }) @@ -93,9 +94,9 @@ public void init() { .permission("carbon.togglemsg") .literal("off", "ignore") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandToggleMsgDescription()) + .commandDescription(richDescription(this.carbonMessages.commandToggleMsgDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); sender.ignoringDirectMessages(true); this.carbonMessages.whispersToggledOff(sender); }) diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/UnignoreCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/UnignoreCommand.java index a46dd43e5..a5056e1ad 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/UnignoreCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/UnignoreCommand.java @@ -19,22 +19,22 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.UUIDArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.UUIDParser.uuidParser; @DefaultQualifier(NonNull.class) public final class UnignoreCommand extends CarbonCommand { @@ -42,19 +42,19 @@ public final class UnignoreCommand extends CarbonCommand { private final UserManager users; private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; @Inject public UnignoreCommand( final UserManager userManager, final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory + final ParserFactory parserFactory ) { this.users = userManager; this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; } @Override @@ -71,18 +71,18 @@ public Key key() { public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) // TODO: Filter, and only show muted players, but allow inputting any player name. - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.carbonMessages.commandUnignoreArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), + richDescription(this.carbonMessages.commandUnignoreArgumentPlayer())) .flag(this.commandManager.flagBuilder("uuid") .withAliases("u") - .withDescription(RichDescription.of(this.carbonMessages.commandUnignoreArgumentUUID())) - .withArgument(UUIDArgument.optional("uuid")) + .withDescription(richDescription(this.carbonMessages.commandUnignoreArgumentUUID())) + .withComponent(uuidParser()) ) .permission("carbon.ignore.unignore") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandUnignoreDescription()) + .commandDescription(richDescription(this.carbonMessages.commandUnignoreDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/UnmuteCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/UnmuteCommand.java index 17e82918f..990a037aa 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/UnmuteCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/UnmuteCommand.java @@ -19,23 +19,23 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.UUIDArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import net.draycia.carbon.api.CarbonServer; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.UUIDParser.uuidParser; @DefaultQualifier(NonNull.class) public final class UnmuteCommand extends CarbonCommand { @@ -44,7 +44,7 @@ public final class UnmuteCommand extends CarbonCommand { private final CarbonServer server; private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; @Inject public UnmuteCommand( @@ -52,13 +52,13 @@ public UnmuteCommand( final CarbonServer server, final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory + final ParserFactory parserFactory ) { this.users = userManager; this.server = server; this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; } @Override @@ -74,18 +74,18 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.carbonMessages.commandUnmuteArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), + richDescription(this.carbonMessages.commandUnmuteArgumentPlayer())) .flag(this.commandManager.flagBuilder("uuid") .withAliases("u") - .withDescription(RichDescription.of(this.carbonMessages.commandUnmuteArgumentUUID())) - .withArgument(UUIDArgument.optional("uuid")) + .withDescription(richDescription(this.carbonMessages.commandUnmuteArgumentUUID())) + .withComponent(uuidParser()) ) .permission("carbon.mute.unmute") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandUnmuteDescription()) + .commandDescription(richDescription(this.carbonMessages.commandUnmuteDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = handler.sender().carbonPlayer(); final CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/UpdateUsernameCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/UpdateUsernameCommand.java index 3723432de..21c9a6270 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/UpdateUsernameCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/UpdateUsernameCommand.java @@ -19,18 +19,14 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.UUIDArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import java.util.Objects; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; import net.draycia.carbon.common.messages.CarbonMessages; import net.draycia.carbon.common.users.CarbonPlayerCommon; @@ -39,6 +35,10 @@ import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.parser.standard.UUIDParser.uuidParser; @DefaultQualifier(NonNull.class) public final class UpdateUsernameCommand extends CarbonCommand { @@ -46,7 +46,7 @@ public final class UpdateUsernameCommand extends CarbonCommand { private final UserManager userManager; private final CommandManager commandManager; private final CarbonMessages messageService; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; private final ProfileResolver profileResolver; @Inject @@ -54,13 +54,13 @@ public UpdateUsernameCommand( final UserManager userManager, final CommandManager commandManager, final CarbonMessages messageService, - final ArgumentFactory argumentFactory, + final ParserFactory parserFactory, final ProfileResolver profileResolver ) { this.userManager = userManager; this.commandManager = commandManager; this.messageService = messageService; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; this.profileResolver = profileResolver; } @@ -77,18 +77,18 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player").asOptional(), - RichDescription.of(this.messageService.commandUpdateUsernameArgumentPlayer())) + .optional("player", this.parserFactory.carbonPlayer(), + richDescription(this.messageService.commandUpdateUsernameArgumentPlayer())) .flag(this.commandManager.flagBuilder("uuid") .withAliases("u") - .withDescription(RichDescription.of(this.messageService.commandUpdateUsernameArgumentUUID())) - .withArgument(UUIDArgument.optional("uuid")) + .withDescription(richDescription(this.messageService.commandUpdateUsernameArgumentUUID())) + .withComponent(uuidParser()) ) .permission("carbon.updateusername") .senderType(Commander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.messageService.commandUpdateUsernameDescription()) + .commandDescription(richDescription(this.messageService.commandUpdateUsernameDescription())) .handler(handler -> { - final CarbonPlayer sender = ((PlayerCommander) handler.getSender()).carbonPlayer(); + final CarbonPlayer sender = ((PlayerCommander) handler.sender()).carbonPlayer(); CarbonPlayer target; if (handler.contains("player")) { diff --git a/common/src/main/java/net/draycia/carbon/common/command/commands/WhisperCommand.java b/common/src/main/java/net/draycia/carbon/common/command/commands/WhisperCommand.java index 3e97549b4..8482acbb4 100644 --- a/common/src/main/java/net/draycia/carbon/common/command/commands/WhisperCommand.java +++ b/common/src/main/java/net/draycia/carbon/common/command/commands/WhisperCommand.java @@ -19,10 +19,6 @@ */ package net.draycia.carbon.common.command.commands; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; -import cloud.commandframework.minecraft.extras.RichDescription; import com.google.inject.Inject; import com.google.inject.Provider; import net.draycia.carbon.api.CarbonServer; @@ -30,12 +26,13 @@ import net.draycia.carbon.api.event.events.CarbonPrivateChatEvent; import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.users.UserManager; -import net.draycia.carbon.common.command.ArgumentFactory; +import net.draycia.carbon.common.RawChat; import net.draycia.carbon.common.command.CarbonCommand; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; +import net.draycia.carbon.common.command.ParserFactory; import net.draycia.carbon.common.command.PlayerCommander; -import net.draycia.carbon.common.command.argument.CarbonPlayerArgument; +import net.draycia.carbon.common.command.argument.CarbonPlayerParser; import net.draycia.carbon.common.config.ConfigManager; import net.draycia.carbon.common.event.events.CarbonPrivateChatEventImpl; import net.draycia.carbon.common.messages.CarbonMessages; @@ -45,6 +42,7 @@ import net.draycia.carbon.common.messaging.packets.WhisperPacket; import net.draycia.carbon.common.users.NetworkUsers; import net.draycia.carbon.common.util.CloudUtils; +import net.kyori.adventure.chat.ChatType; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; @@ -52,25 +50,30 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.minecraft.signed.SignedString; + +import static org.incendo.cloud.minecraft.extras.RichDescription.richDescription; +import static org.incendo.cloud.minecraft.signed.SignedGreedyStringParser.signedGreedyStringParser; @DefaultQualifier(NonNull.class) public final class WhisperCommand extends CarbonCommand { private final CommandManager commandManager; private final CarbonMessages carbonMessages; - private final ArgumentFactory argumentFactory; + private final ParserFactory parserFactory; private final WhisperHandler whisper; @Inject public WhisperCommand( final CommandManager commandManager, final CarbonMessages carbonMessages, - final ArgumentFactory argumentFactory, + final ParserFactory parserFactory, final WhisperHandler whisper ) { this.commandManager = commandManager; this.carbonMessages = carbonMessages; - this.argumentFactory = argumentFactory; + this.parserFactory = parserFactory; this.whisper = whisper; } @@ -87,25 +90,23 @@ public Key key() { @Override public void init() { final var command = this.commandManager.commandBuilder(this.commandSettings().name(), this.commandSettings().aliases()) - .argument(this.argumentFactory.carbonPlayer("player"), - RichDescription.of(this.carbonMessages.commandWhisperArgumentPlayer())) - .argument(StringArgument.greedy("message"), - RichDescription.of(this.carbonMessages.commandWhisperArgumentMessage())) + .required("player", this.parserFactory.carbonPlayer(), richDescription(this.carbonMessages.commandWhisperArgumentPlayer())) + .required("message", signedGreedyStringParser(), richDescription(this.carbonMessages.commandWhisperArgumentMessage())) .permission("carbon.whisper.message") .senderType(PlayerCommander.class) - .meta(MinecraftExtrasMetaKeys.DESCRIPTION, this.carbonMessages.commandWhisperDescription()) + .commandDescription(richDescription(this.carbonMessages.commandWhisperDescription())) .handler(ctx -> { - final CarbonPlayer sender = ((PlayerCommander) ctx.getSender()).carbonPlayer(); + final CarbonPlayer sender = ctx.sender().carbonPlayer(); if (sender.muted()) { this.carbonMessages.muteCannotSpeak(sender); return; } - final String message = ctx.get("message"); + final SignedString message = ctx.get("message"); final CarbonPlayer recipient = ctx.get("player"); - this.whisper.whisper(sender, recipient, message, ctx.getOrDefault(CarbonPlayerArgument.Parser.INPUT_STRING, null)); + this.whisper.whisper(sender, recipient, message, ctx.parsingContext("player").consumedInput()); }) .build(); @@ -123,6 +124,7 @@ public static final class WhisperHandler { private final CarbonServer server; private final CarbonEventHandler events; private final NetworkUsers network; + private final Key rawChatKey; @Inject private WhisperHandler( @@ -134,7 +136,8 @@ private WhisperHandler( final UserManager userManager, final CarbonServer server, final CarbonEventHandler events, - final NetworkUsers network + final NetworkUsers network, + @RawChat final Key rawChatKey ) { this.logger = logger; this.messages = messages; @@ -145,12 +148,13 @@ private WhisperHandler( this.server = server; this.events = events; this.network = network; + this.rawChatKey = rawChatKey; } public void whisper( final CarbonPlayer sender, final CarbonPlayer recipient, - final String message + final SignedString message ) { this.whisper(sender, recipient, message, null); } @@ -158,7 +162,7 @@ public void whisper( public void whisper( final CarbonPlayer sender, final CarbonPlayer recipient, - final String message, + final SignedString message, final @Nullable String recipientInputString ) { if (sender.equals(recipient)) { @@ -173,7 +177,7 @@ public void whisper( final String recipientUsername = recipient.username(); if (!this.network.online(recipient) || !sender.awareOf(recipient) && !sender.hasPermission("carbon.whisper.vanished")) { - final var exception = new CarbonPlayerArgument.ParseException( + final var exception = new CarbonPlayerParser.ParseException( recipientInputString == null ? recipientUsername : recipientInputString, this.messages ); @@ -201,7 +205,7 @@ public void whisper( final Component senderDisplayName = sender.displayName(); final Component recipientDisplayName = recipient.displayName(); - final CarbonPrivateChatEvent privateChatEvent = new CarbonPrivateChatEventImpl(sender, recipient, Component.text(message)); + final CarbonPrivateChatEvent privateChatEvent = new CarbonPrivateChatEventImpl(sender, recipient, Component.text(message.string())); this.events.emit(privateChatEvent); if (privateChatEvent.cancelled()) { @@ -210,9 +214,17 @@ public void whisper( } final String senderUsername = sender.username(); - this.messages.whisperSender(SourcedAudience.of(sender, sender), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, privateChatEvent.message()); + message.sendMessage( + sender, + ChatType.chatType(this.rawChatKey), + this.messages.whisperSender(SourcedAudience.of(sender, sender), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, privateChatEvent.message()) + ); if (localRecipient) { - this.messages.whisperRecipient(SourcedAudience.of(sender, recipient), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, privateChatEvent.message()); + message.sendMessage( + recipient, + ChatType.chatType(this.rawChatKey), + this.messages.whisperRecipient(SourcedAudience.of(sender, recipient), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, privateChatEvent.message()) + ); } this.messages.whisperConsoleLog(this.server.console(), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, privateChatEvent.message()); @@ -245,7 +257,9 @@ public void handlePacket(final WhisperPacket packet) { final Component recipientDisplayName = recipient.displayName(); recipient.whisperReplyTarget(sender.uuid()); - this.messages.whisperRecipient(SourcedAudience.of(sender, recipient), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, packet.message()); + SourcedAudience.of(sender, recipient).sendMessage( + this.messages.whisperRecipient(SourcedAudience.of(sender, recipient), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, packet.message()) + ); this.messages.whisperConsoleLog(this.server.console(), senderUsername, senderDisplayName, recipientUsername, recipientDisplayName, packet.message()); final @Nullable Sound messageSound = this.configManager.primaryConfig().messageSound(); if (messageSound != null) { diff --git a/common/src/main/java/net/draycia/carbon/common/config/PrimaryConfig.java b/common/src/main/java/net/draycia/carbon/common/config/PrimaryConfig.java index f0bc93e64..dba8af68c 100644 --- a/common/src/main/java/net/draycia/carbon/common/config/PrimaryConfig.java +++ b/common/src/main/java/net/draycia/carbon/common/config/PrimaryConfig.java @@ -47,6 +47,9 @@ public class PrimaryConfig { If the channel is not found or the player cannot use the channel, they will speak in basic non-channel chat.""") private Key defaultChannel = Key.key("carbon", "global"); + @Comment("Returns you to the default channel when you use a channel's command while you have that channel active.") + private boolean returnToDefaultChannel = false; + @Comment(""" The service that will be used to store and load player information. One of: JSON, H2, MYSQL, PSQL @@ -114,6 +117,10 @@ public Key defaultChannel() { return this.defaultChannel; } + public boolean returnToDefaultChannel() { + return this.returnToDefaultChannel; + } + public StorageType storageType() { return this.storageType; } @@ -186,14 +193,13 @@ public boolean updateChecker() { public static void upgrade(final ConfigurationNode node) { final ConfigurationTransformation.VersionedBuilder builder = ConfigurationTransformation.versionedBuilder() .versionKey(ConfigManager.CONFIG_VERSION_KEY); - final ConfigurationTransformation initial = ConfigurationTransformation.builder() - .addAction(NodePath.path("use-carbon-nicknames"), (path, value) -> new Object[]{"nickname-settings", "use-carbon-nicknames"}) - .build(); - builder.addVersion(0, initial); - final ConfigurationTransformation one = ConfigurationTransformation.builder() - .addAction(NodePath.path("party-chat"), (path, value) -> new Object[]{"party-chat", "enabled"}) - .build(); - builder.addVersion(1, one); + + builder.addVersion(0, insertAddition("use-carbon-nicknames", "nickname-settings", "use-carbon-nicknames")); + builder.addVersion(1, insertAddition("party-chat", "party-chat", "enabled")); + builder.addVersion(2, insertAddition("nickname-settings", "filter", ".*")); + builder.addVersion(3, insertAddition("return-to-default-channel", "return-to-default-channel", false)); + builder.addVersion(4, insertAddition("nickname-settings", "update-tab-list", true)); + final ConfigurationTransformation.Versioned upgrader = builder.build(); final int from = upgrader.version(node); try { @@ -205,12 +211,21 @@ public static void upgrade(final ConfigurationNode node) { ConfigManager.configVersionComment(node, upgrader); } + private static ConfigurationTransformation insertAddition(final String path, final Object key, final Object value) { + return ConfigurationTransformation.builder() + .addAction(NodePath.path(path), ($, $$) -> new Object[]{key, value}) + .build(); + } + @ConfigSerializable public static final class NicknameSettings { @Comment("Whether Carbon's nickname management should be used. Disable this if you wish to have another plugin manage nicknames.") private boolean useCarbonNicknames = true; + @Comment("Paper only. Updates the player's display name in the tab list to match their nickname.") + private boolean updateTabList = true; + @Comment("Minimum number of characters in nickname (excluding formatting).") private int minLength = 3; @@ -219,6 +234,9 @@ public static final class NicknameSettings { private List blackList = List.of("notch", "admin"); + @Comment("Regex pattern nicknames must match in order to be applied, can be bypassed with the permission 'carbon.nickname.filter'.") + private String filter = "^[a-zA-Z0-9_]*$"; + @Comment("Format used when displaying nicknames.") public String format = "@'>~"; @@ -229,10 +247,18 @@ public boolean useCarbonNicknames() { return this.useCarbonNicknames; } + public boolean updateTabList() { + return this.updateTabList; + } + public List blackList() { return this.blackList; } + public String filter() { + return this.filter; + } + public int minLength() { return this.minLength; } diff --git a/common/src/main/java/net/draycia/carbon/common/listeners/ChatListenerInternal.java b/common/src/main/java/net/draycia/carbon/common/listeners/ChatListenerInternal.java index d89587af7..727a35d4f 100644 --- a/common/src/main/java/net/draycia/carbon/common/listeners/ChatListenerInternal.java +++ b/common/src/main/java/net/draycia/carbon/common/listeners/ChatListenerInternal.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import net.draycia.carbon.api.channels.ChannelPermissionResult; import net.draycia.carbon.api.channels.ChatChannel; import net.draycia.carbon.api.event.CarbonEventHandler; import net.draycia.carbon.api.users.CarbonPlayer; @@ -69,6 +70,26 @@ protected ChatListenerInternal( } protected @Nullable CarbonChatEventImpl prepareAndEmitChatEvent(final CarbonPlayer sender, final String messageContent, final @Nullable SignedMessage signedMessage, final ChatChannel channel) { + final ChannelPermissionResult permitted = channel.speechPermitted(sender); + if (!permitted.permitted()) { + sender.sendMessage(permitted.reason()); + return null; + } + + if (!sender.hasPermission("carbon.cooldown.exempt") && channel.cooldown() > 0) { + final long currentMillis = System.currentTimeMillis(); + final long expiresAt = channel.playerCooldown(sender); + + if (currentMillis < expiresAt) { + // Round up, or the player can be told they have 0 seconds remaining + final long remaining = (long) Math.ceil((double) (expiresAt - currentMillis) / 1000); + this.carbonMessages.channelCooldown(sender, remaining); + return null; + } + + channel.startCooldown(sender); + } + String content = this.configManager.primaryConfig().applyChatPlaceholders(messageContent); content = this.configManager.primaryConfig().applyChatFilters(content); diff --git a/common/src/main/java/net/draycia/carbon/common/listeners/ItemLinkHandler.java b/common/src/main/java/net/draycia/carbon/common/listeners/ItemLinkHandler.java index 5622c903e..0ccb48d57 100644 --- a/common/src/main/java/net/draycia/carbon/common/listeners/ItemLinkHandler.java +++ b/common/src/main/java/net/draycia/carbon/common/listeners/ItemLinkHandler.java @@ -22,7 +22,10 @@ import com.google.inject.Inject; import net.draycia.carbon.api.event.CarbonEventHandler; import net.draycia.carbon.api.event.events.CarbonChatEvent; +import net.draycia.carbon.api.event.events.CarbonPrivateChatEvent; +import net.draycia.carbon.api.users.CarbonPlayer; import net.draycia.carbon.api.util.InventorySlot; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; public class ItemLinkHandler implements Listener { @@ -30,27 +33,34 @@ public class ItemLinkHandler implements Listener { @Inject public ItemLinkHandler(final CarbonEventHandler events) { events.subscribe(CarbonChatEvent.class, 2, false, event -> { - if (!event.sender().hasPermission("carbon.itemlink")) { - return; - } + event.message(this.handleChatEvent(event.sender(), event.message())); + }); - for (final var slot : InventorySlot.SLOTS) { - for (final var placeholder : slot.placeholders()) { - event.message( - event.message() - .replaceText(TextReplacementConfig.builder() - .matchLiteral("<" + placeholder + ">") - // .once() - .replacement(builder -> { - final var itemComponent = event.sender().createItemHoverComponent(slot); - - return itemComponent == null ? builder : itemComponent; - }) - .build()) - ); - } - } + events.subscribe(CarbonPrivateChatEvent.class, 2, false, event -> { + event.message(this.handleChatEvent(event.sender(), event.message())); }); } + private Component handleChatEvent(final CarbonPlayer sender, Component message) { + if (!sender.hasPermission("carbon.itemlink")) { + return message; + } + + for (final var slot : InventorySlot.SLOTS) { + for (final var placeholder : slot.placeholders()) { + message = message + .replaceText(TextReplacementConfig.builder() + .matchLiteral("<" + placeholder + ">") + .replacement(builder -> { + final Component itemComponent = sender.createItemHoverComponent(slot); + + return itemComponent == null ? builder : itemComponent; + }) + .build()); + } + } + + return message; + } + } diff --git a/common/src/main/java/net/draycia/carbon/common/messages/CarbonMessages.java b/common/src/main/java/net/draycia/carbon/common/messages/CarbonMessages.java index 74f6748c5..7c1528798 100644 --- a/common/src/main/java/net/draycia/carbon/common/messages/CarbonMessages.java +++ b/common/src/main/java/net/draycia/carbon/common/messages/CarbonMessages.java @@ -56,6 +56,9 @@ public interface CarbonMessages { @Message("channel.joined") void channelJoined(final Audience audience); + @Message("channel.cooldown") + void channelCooldown(final Audience audience, long remaining); + /* * ============================================================= * =========================== Mutes =========================== @@ -108,8 +111,8 @@ public interface CarbonMessages { */ @Message("whisper.to") - void whisperSender( - SourcedAudience audience, + Component whisperSender( + @NotPlaceholder SourcedAudience audience, String senderUsername, Component senderDisplayName, String recipientUsername, @@ -118,8 +121,8 @@ void whisperSender( ); @Message("whisper.from") - void whisperRecipient( - SourcedAudience audience, + Component whisperRecipient( + @NotPlaceholder SourcedAudience audience, String senderUsername, Component senderDisplayName, String recipientUsername, @@ -197,6 +200,9 @@ void nicknameErrorCharacterLimit( @Message("nickname.error.blacklist") void nicknameErrorBlackList(final Audience audience, final Component nickname); + @Message("nickname.error.filter") + void nicknameErrorFilter(final Audience audience, final Component nickname); + @Message("nickname.show.others") void nicknameShowOthers(final Audience audience, final String target, final Component nickname); diff --git a/common/src/main/java/net/draycia/carbon/common/messages/NotPlaceholder.java b/common/src/main/java/net/draycia/carbon/common/messages/NotPlaceholder.java new file mode 100644 index 000000000..febfa824f --- /dev/null +++ b/common/src/main/java/net/draycia/carbon/common/messages/NotPlaceholder.java @@ -0,0 +1,32 @@ +/* + * CarbonChat + * + * Copyright (c) 2024 Josua Parks (Vicarious) + * 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 net.draycia.carbon.common.messages; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Target({ElementType.PARAMETER, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotPlaceholder { +} diff --git a/common/src/main/java/net/draycia/carbon/common/messages/StandardPlaceholderResolverStrategyButDifferent.java b/common/src/main/java/net/draycia/carbon/common/messages/StandardPlaceholderResolverStrategyButDifferent.java index 9f7f0e0e6..74710a766 100644 --- a/common/src/main/java/net/draycia/carbon/common/messages/StandardPlaceholderResolverStrategyButDifferent.java +++ b/common/src/main/java/net/draycia/carbon/common/messages/StandardPlaceholderResolverStrategyButDifferent.java @@ -81,7 +81,7 @@ public StandardPlaceholderResolverStrategyButDifferent(final NamingScheme placeh final Parameter parameter = methodParameters[idx]; final @Nullable Object value = parameters[idx]; // Don't resolve Audiences for now - if (value == null || parameter.getType() == Audience.class) { + if (value == null || parameter.getType() == Audience.class || parameter.getAnnotation(NotPlaceholder.class) != null) { // Nothing to resolve with. continue; } diff --git a/common/src/main/java/net/draycia/carbon/common/messages/placeholders/LongPlaceholderResolver.java b/common/src/main/java/net/draycia/carbon/common/messages/placeholders/LongPlaceholderResolver.java new file mode 100644 index 000000000..3d5d06d1f --- /dev/null +++ b/common/src/main/java/net/draycia/carbon/common/messages/placeholders/LongPlaceholderResolver.java @@ -0,0 +1,46 @@ +/* + * CarbonChat + * + * Copyright (c) 2024 Josua Parks (Vicarious) + * 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 net.draycia.carbon.common.messages.placeholders; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Map; +import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.moonshine.placeholder.ConclusionValue; +import net.kyori.moonshine.placeholder.ContinuanceValue; +import net.kyori.moonshine.placeholder.IPlaceholderResolver; +import net.kyori.moonshine.util.Either; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class LongPlaceholderResolver implements IPlaceholderResolver { + + @Override + public @Nullable Map, ContinuanceValue>> resolve( + final String placeholderName, + final Long value, + final R receiver, + final Type owner, + final Method method, + final @Nullable Object[] parameters + ) { + return Map.of(placeholderName, Either.left(ConclusionValue.conclusionValue(Tag.preProcessParsed(String.valueOf(value))))); + } + +} diff --git a/common/src/main/java/net/draycia/carbon/common/users/NetworkUsers.java b/common/src/main/java/net/draycia/carbon/common/users/NetworkUsers.java index 7ae257763..7a58b6d0a 100644 --- a/common/src/main/java/net/draycia/carbon/common/users/NetworkUsers.java +++ b/common/src/main/java/net/draycia/carbon/common/users/NetworkUsers.java @@ -19,7 +19,6 @@ */ package net.draycia.carbon.common.users; -import cloud.commandframework.context.CommandContext; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.List; @@ -43,6 +42,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.suggestion.Suggestion; /** * Eventually consistent store of who is on each server in the network (besides self). @@ -97,15 +99,18 @@ public void handlePacket(final LocalPlayersPacket packet) { // PlayerSuggestions impl @Override - public List apply(final CommandContext ctx, final String input) { - final Commander commander = ctx.getSender(); + public CompletableFuture> suggestionsFuture(final CommandContext ctx, final CommandInput input) { + final Commander commander = ctx.sender(); final List local = this.server.players(); if (!(commander instanceof PlayerCommander player)) { - return Stream.concat(local.stream().map(CarbonPlayer::username), this.map.values().stream().flatMap(m -> m.values().stream())) - .distinct() - .toList(); + return CompletableFuture.completedFuture( + Stream.concat(local.stream().map(CarbonPlayer::username), this.map.values().stream().flatMap(m -> m.values().stream())) + .distinct() + .map(Suggestion::suggestion) + .toList() + ); } final CarbonPlayer carbonPlayer = player.carbonPlayer(); @@ -125,11 +130,14 @@ public List apply(final CommandContext ctx, final String inpu .map(future -> future.getNow(null)) .filter(Objects::nonNull); - return Stream.concat(local.stream(), remote) - .filter(carbonPlayer::awareOf) - .map(CarbonPlayer::username) - .distinct() - .toList(); + return CompletableFuture.completedFuture( + Stream.concat(local.stream(), remote) + .filter(carbonPlayer::awareOf) + .map(CarbonPlayer::username) + .distinct() + .map(Suggestion::suggestion) + .toList() + ); } public boolean online(final CarbonPlayer player) { diff --git a/common/src/main/java/net/draycia/carbon/common/util/CloudUtils.java b/common/src/main/java/net/draycia/carbon/common/util/CloudUtils.java index 9bd39f260..119db4c80 100644 --- a/common/src/main/java/net/draycia/carbon/common/util/CloudUtils.java +++ b/common/src/main/java/net/draycia/carbon/common/util/CloudUtils.java @@ -19,19 +19,11 @@ */ package net.draycia.carbon.common.util; -import cloud.commandframework.CommandManager; -import cloud.commandframework.exceptions.ArgumentParseException; -import cloud.commandframework.exceptions.CommandExecutionException; -import cloud.commandframework.exceptions.InvalidCommandSenderException; -import cloud.commandframework.exceptions.InvalidSyntaxException; -import cloud.commandframework.exceptions.NoPermissionException; -import cloud.commandframework.execution.FilteringCommandSuggestionProcessor; import com.google.inject.Inject; import com.google.inject.Provider; import java.io.PrintWriter; import java.io.StringWriter; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -46,9 +38,19 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.util.ComponentMessageThrowable; +import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.exception.ArgumentParseException; +import org.incendo.cloud.exception.CommandExecutionException; +import org.incendo.cloud.exception.InvalidCommandSenderException; +import org.incendo.cloud.exception.InvalidSyntaxException; +import org.incendo.cloud.exception.NoPermissionException; +import org.incendo.cloud.util.TypeUtils; + +import static org.incendo.cloud.exception.handling.ExceptionHandler.unwrappingHandler; @DefaultQualifier(NonNull.class) public final class CloudUtils { @@ -88,75 +90,49 @@ public static Component message(final Throwable throwable) { return msg == null ? NULL : msg; } - public static String rawInputByMatchingName( - final LinkedList rawInput, - final CarbonPlayer recipient - ) { - return rawInput - .stream() - .filter(it -> it.equalsIgnoreCase(recipient.username())) - .findFirst() - .orElse(recipient.username()); - } - public static void decorateCommandManager( final CommandManager commandManager, - final CarbonMessages carbonMessages + final CarbonMessages carbonMessages, + final Logger logger ) { - commandManager.commandSuggestionProcessor( - new FilteringCommandSuggestionProcessor<>( - FilteringCommandSuggestionProcessor.Filter.contains(true).andTrimBeforeLastSpace() - ) - ); - - registerExceptionHandlers(commandManager, carbonMessages); + registerExceptionHandlers(commandManager, carbonMessages, logger); } public static void registerExceptionHandlers( final CommandManager commandManager, - final CarbonMessages carbonMessages + final CarbonMessages carbonMessages, + final Logger logger ) { - commandManager.registerExceptionHandler(ArgumentParseException.class, (sender, exception) -> { - final var throwableMessage = CloudUtils.message(exception.getCause()); - - carbonMessages.errorCommandArgumentParsing(sender, throwableMessage); - }); - commandManager.registerExceptionHandler(InvalidCommandSenderException.class, (sender, exception) -> { - final var senderType = exception.getRequiredSender().getSimpleName(); - - carbonMessages.errorCommandInvalidSender(sender, senderType); - }); - commandManager.registerExceptionHandler(InvalidSyntaxException.class, (sender, exception) -> { - final var syntax = - Component.text(exception.getCorrectSyntax()).replaceText( + commandManager.exceptionController() + .registerHandler(ArgumentParseException.class, ctx -> + carbonMessages.errorCommandArgumentParsing(ctx.context().sender(), CloudUtils.message(ctx.exception().getCause()))) + .registerHandler(InvalidCommandSenderException.class, ctx -> + carbonMessages.errorCommandInvalidSender(ctx.context().sender(), TypeUtils.simpleName(ctx.exception().requiredSender()))) + .registerHandler(InvalidSyntaxException.class, ctx -> + carbonMessages.errorCommandInvalidSyntax(ctx.context().sender(), Component.text(ctx.exception().correctSyntax()).replaceText( config -> config.match(SPECIAL_CHARACTERS_PATTERN) - .replacement(match -> match.color(NamedTextColor.WHITE))); - - carbonMessages.errorCommandInvalidSyntax(sender, syntax); - }); - commandManager.registerExceptionHandler(NoPermissionException.class, (sender, exception) -> { - carbonMessages.errorCommandNoPermission(sender); - }); - commandManager.registerExceptionHandler(CommandExecutionException.class, (sender, exception) -> { - final Throwable cause = exception.getCause(); - - if (cause instanceof CommandCompleted completed) { - final @Nullable Component msg = completed.componentMessage(); + .replacement(match -> match.color(NamedTextColor.WHITE))))) + .registerHandler(NoPermissionException.class, ctx -> + carbonMessages.errorCommandNoPermission(ctx.context().sender())) + .registerHandler(CommandExecutionException.class, ctx -> { + final Throwable cause = ctx.exception().getCause(); + + logger.warn("Unexpected exception executing command", cause); + + final StringWriter writer = new StringWriter(); + cause.printStackTrace(new PrintWriter(writer)); + final String stackTrace = writer.toString().replaceAll("\t", " "); + final @Nullable Component throwableMessage = CloudUtils.message(cause); + + carbonMessages.errorCommandCommandExecution(ctx.context().sender(), throwableMessage, stackTrace); + }) + .registerHandler(CommandExecutionException.class, unwrappingHandler(CommandCompleted.class)) + .registerHandler(CommandCompleted.class, ctx -> { + final @Nullable Component msg = ctx.exception().componentMessage(); if (msg != null) { - sender.sendMessage(msg); + ctx.context().sender().sendMessage(msg); } - return; - } - - cause.printStackTrace(); - - final StringWriter writer = new StringWriter(); - cause.printStackTrace(new PrintWriter(writer)); - final String stackTrace = writer.toString().replaceAll("\t", " "); - final @Nullable Component throwableMessage = CloudUtils.message(cause); - - carbonMessages.errorCommandCommandExecution(sender, throwableMessage, stackTrace); - }); + }); } public static CarbonPlayer nonPlayerMustProvidePlayer(final CarbonMessages messages, final Commander commander) { diff --git a/common/src/main/resources/locale/messages-en_US.properties b/common/src/main/resources/locale/messages-en_US.properties index 8c42f2e35..1d8435b8d 100644 --- a/common/src/main/resources/locale/messages-en_US.properties +++ b/common/src/main/resources/locale/messages-en_US.properties @@ -127,6 +127,7 @@ nickname.show.unset=You do not have a nickname set nickname.show=Your nickname is nickname.error.character_limit=Nickname "" has exceeded the character limit. Must be set to ~ characters. nickname.error.blacklist=Nickname "" is not allowed. Please choose another name. +nickname.error.filter=Nicknames must be alphanumeric! reply.target.missing=You have no-one to reply to reply.target.self=You cannot whisper to yourself whisper.console=[] -> [] @@ -139,6 +140,7 @@ whisper.ignoring_all=You cannot send messages while they are ignored! whisper.to= '>'>[You] -> [] whisper.toggled.on=Now receiving private messages. whisper.toggled.off=No longer receiving private messages. +channel.cooldown=You may use chat again in seconds! channel.radius.empty_recipients=You're not close enough to anyone to send a message channel.joined=You have rejoined the channel channel.left=You have left the channel diff --git a/common/src/main/resources/locale/messages-ja_JP.properties b/common/src/main/resources/locale/messages-ja_JP.properties index 61c966496..33303208c 100644 --- a/common/src/main/resources/locale/messages-ja_JP.properties +++ b/common/src/main/resources/locale/messages-ja_JP.properties @@ -2,6 +2,7 @@ channel.change=メッセージを送信中 command.clearchat.description=すべてのプレイヤーのチャットウィンドウをクリアします。 command.continue.argument.message=送信するメッセージです。 command.continue.description=最後にメッセージを送った人にメッセージを送信します。 +command.debug.argument.player=プレーヤーのグループをチェックする。 command.debug.description=プレイヤーの権限グループを表示します。 command.help.argument.query=検索クエリ。 command.help.description=Carbonのコマンドリストです。 @@ -21,6 +22,12 @@ command.help.misc.showing_results_for_query=クエリの検索結果を表示中 command.ignore.argument.player=無視するプレーヤーの名前。 command.ignore.argument.uuid=無視するプレーヤーのUUID。 command.ignore.description=無視したプレイヤーからのすべてのメッセージを非表示にします。 +command.ignorelist.description=あなたが無視しているプレイヤーのリストをページ順に表示する。 +command.ignorelist.none_ignored=あなたは他のプレイヤーを無視していません。 +command.ignorelist.pagination_header=無視したプレイヤー +command.ignorelist.pagination_element= - ''>''>[unignore] +command.join.description=以前に退出したチャンネルに加入する。 +command.leave.description=現在アクセスしているチャンネルから退出する。 command.mute.argument.player=ミュートするプレーヤーの名前。 command.mute.argument.uuid=ミュートするプレーヤーのUUID。 command.mute.description=プレイヤーをミュートし、チャットや他のプレイヤーへのプライベートメッセージを禁止します。 @@ -30,18 +37,58 @@ command.muteinfo.description=プレイヤーがミュートかどうかを表示 command.nickname.argument.nickname=設定するニックネーム。 command.nickname.argument.player=ターゲットプレイヤーの名前。このフラグがなければ、送信者がターゲットになります。 command.nickname.description=プレイヤーのニックネームを設定および表示します。 +command.nickname.set.description=あなたのニックネームを設定する。 +command.nickname.reset.description=あなたのニックネームを削除する。 +command.nickname.others.description=プレイヤーのニックネームを表示する。 +command.nickname.others.set.description=プレイヤーのニックネームを設定する。 +command.nickname.others.reset.description=ターゲットから設定されたニックネームを削除する。 command.reload.description=Carbonの設定、チャンネル設定、翻訳をリロードします。チャンネルをロードしたり、アンロードしたりしません。 command.reply.argument.message=返信するメッセージ。 command.reply.description=最後にメッセージを送ったプレイヤーにメッセージを送信します。 +command.togglemsg.description=他のプレイヤーからあなたへのメッセージを許可/拒否する。 command.unignore.argument.player=無視を解除するプレーヤーの名前。 command.unignore.argument.uuid=無視を解除するプレイヤーのUUID。 command.unignore.description=指定したプレイヤーからのメッセージの非表示を停止します。 command.unmute.argument.player=ミュートを解除するプレーヤーの名前。 command.unmute.argument.uuid=ミュートを解除するプレーヤーのUUID。 command.unmute.description=プレイヤーのミュートを解除し、チャットや他のプレイヤーへのプライベートメッセージを使用できるようにします。 +command.updateusername.argument.player=更新するプレイヤーの名前。 +command.updateusername.argument.uuid=更新するプレーヤーのuuid。 +command.updateusername.description=プレイヤーのユーザー名をmojangの名前と一致するように更新する。 +command.updateusername.fetching=ユーザー名を取得中... +command.updateusername.notupdated=ユーザー名を取得できません。 +command.updateusername.updated=のユーザー名を更新しました! command.whisper.argument.message=送信するメッセージ。 command.whisper.argument.player=メッセージを送信するプレーヤーの名前。 command.whisper.description=指定したプレーヤーにプライベートメッセージを送信します。 +command.party.pagination_header=パーティーメンバー\: +command.party.pagination_element=''\:''''> - +command.party.created=パーティー「」の作成と参加に成功しました! +command.party.not_in_party=あなたはパーティーに参加していません。パーティを作成するには「/party create」を、招待を承認するには「/party accept」を使用して下さい。 +command.party.current_party=あなたが参加しているパーティー\: +command.party.must_leave_current_first=あなたはまず現在のパーティーから退出しなければなりません。 +command.party.name_too_long=パーティー名が長すぎます。 +command.party.received_invite=クリックして承認''>''>あなたはからパーティー「」に招待されました。承認するにはこのメッセージをクリックして下さい。 +command.party.sent_invite=にパーティーの招待状を送信しました。 +command.party.must_specify_invite=あなたは誰の招待を承認するか指定しなければなりません。 +command.party.no_pending_invites=あなたには保留中のパーティー招待状はありません。 +command.party.no_invite_from=あなたはからの保留中の招待状はありません。 +command.party.joined_party=パーティー「」の参加に成功しました! +command.party.left_party=パーティー「」の退出に成功しました! +command.party.disbanded=パーティー「」の解散に成功しました! +command.party.cannot_disband_multiple_members=あなたは最後のメンバーではないため、パーティー「」を解散できません。 +command.party.must_be_in_party=このコマンドを使うには、パーティーに入っていなければなりません。パーティを作成するには「/party create」を、招待を承認するには「/party accept」を使用して下さい。 +command.party.cannot_invite_self=自分を招待することはできません。 +command.party.description=現在参加しているパーティーのメンバー情報を確認する。 +command.party.create.description=新しいパーティーを作成する。 +command.party.invite.description=プレイヤーをあなたのパーティーに招待する。 +command.party.accept.description=パーティーへの招待を承認する。 +command.party.leave.description=現在のパーティーから退出する。 +command.party.already_in_party=は既にあなたのパーティーに参加しています。 +command.party.disband.description=現在のパーティーを解散する。 +party.player_joined=があなたのパーティーに参加しました。 +party.player_left=があなたのパーティーを退出しました。 +party.cannot_use_channel=このチャンネルを使用するには、あなたはパーティーに参加する必要があります。 config.reload.failed=コンフィグのリロードに失敗 config.reload.success=コンフィグのリロードに成功 error.command.argument_parsing=無効なコマンド引数: @@ -50,6 +97,9 @@ error.command.invalid_player=入力したプレイヤー''''が見つか error.command.invalid_sender=無効なコマンド送信者。 型である必要があります error.command.invalid_syntax=無効なコマンド構文です。正しいコマンド構文\: / error.command.no_permission=申し訳ありませんが、このコマンドを実行する権限がありません。これがエラーだと思われる場合は、サーバー管理者にお問い合わせください。 +error.command.command_needs_player=非プレイヤーがこのコマンドを実行するには、プレーヤーの引数を指定しなければなりません。 +ignore.already_ignored=あなたは既にを無視しています +ignore.not_ignored=あなたはを無視していません ignore.exempt=あなたはを無視する事はできません ignore.invalid_target=ターゲットが見つかりません ignore.now_ignoring=あなたはを無視しています @@ -75,10 +125,35 @@ nickname.show.others.unset=にはニックネームが設定され nickname.show.others=のニックネームはです nickname.show.unset=あなたはニックネームが設定されていません nickname.show=あなたのニックネームはです +nickname.error.character_limit=ニックネーム「」は文字数制限を超えています。 文字に設定する必要があります。 +nickname.error.blacklist=ニックネーム「」は使用できません。他の名前を入力して下さい。 reply.target.missing=返信できる人がいません reply.target.self=自分自身にプライベートメッセージを送信することはできません +whisper.console=[] -> [] whisper.continue.target_missing=プライベートメッセージを送る相手がいません +whisper.error=プライベートメッセージの送信に失敗しました。 whisper.from=[] -> [あなた] whisper.ignored_by_target=はあなたを無視しています whisper.ignoring_target=あなたはを無視しています +whisper.ignoring_all=無視されている間はメッセージを送信できません! whisper.to=[あなた] -> [] +whisper.toggled.on=プライベートメッセージを受信しています。 +whisper.toggled.off=プライベートメッセージを受信しなくなりました。 +channel.radius.empty_recipients=メッセージを送信できる人が近くには誰もいません。 +channel.joined=チャンネルに再加入しました +channel.left=あなたはチャンネルから退出しました +channel.no_permission=あなたにはこのチャンネルを使用する権限がありません +channel.already_left=あなたはすでにこのチャンネルから退出しています +channel.not_left=あなたはこのチャンネルから退出していません +channel.not_found=チャンネルが見つかりません +pagination.page_out_of_range= ページは範囲外です!ページまでです。 +pagination.click_for_next_page=クリックして次のページへ +pagination.click_for_previous_page=クリックして前のページへ +pagination.footer=ページ / +integrations.towny.cannot_use_alliance_channel=このチャンネルを利用するには、同盟に参加する必要があります。 +integrations.towny.cannot_use_nation_channel=このチャンネルを利用するには、国家に参加する必要があります。 +integrations.towny.cannot_use_town_channel=このチャンネルを利用するには、町に参加する必要があります。 +integrations.mcmmo.cannot_use_party_channel=このチャンネルを利用するには、mcMMOパーティーに参加する必要があります。 +integrations.fuuid.cannot_use_faction_channel=このチャンネルを利用するには、派閥に参加する必要があります。 +integrations.fuuid.cannot_use_alliance_channel=このチャンネルを利用するには、同盟に参加する必要があります。 +integrations.fuuid.cannot_use_truce_channel=このチャンネルを利用するには、他の派閥と休戦する必要があります。 diff --git a/common/src/main/resources/locale/messages-zh_CN.properties b/common/src/main/resources/locale/messages-zh_CN.properties index b1424d59c..b56115368 100644 --- a/common/src/main/resources/locale/messages-zh_CN.properties +++ b/common/src/main/resources/locale/messages-zh_CN.properties @@ -126,6 +126,7 @@ nickname.show.others= 的昵称是 nickname.show.unset=你未设置昵称 nickname.show=你的昵称是 nickname.error.character_limit=昵称 '''' 超过了字符限制, 必须设置为 ~ 个字符. +nickname.error.blacklist=昵称"" 不允许使用, 请选择其他昵称. reply.target.missing=没有回复 reply.target.self=你不能给自己发送私信 whisper.console=[] -> [] diff --git a/common/src/main/resources/locale/messages-zh_TW.properties b/common/src/main/resources/locale/messages-zh_TW.properties index ed71739b8..4bbc836a3 100644 --- a/common/src/main/resources/locale/messages-zh_TW.properties +++ b/common/src/main/resources/locale/messages-zh_TW.properties @@ -1,4 +1,4 @@ -channel.change=你正在 頻道上聊天 +channel.change=你現在正在屏蔽 command.clearchat.description=清空所有玩家的聊天框. command.continue.argument.message=要發送的消息. command.continue.description=嚮你上次私信你的人發送消息. @@ -126,6 +126,7 @@ nickname.show.others= 的昵稱是 nickname.show.unset=你未設定昵稱 nickname.show=你的昵稱是 nickname.error.character_limit=昵稱 '''' 超過了字符限製, 必須設定為 ~ 個字符. +nickname.error.blacklist=昵稱"" 不允許使用, 請選擇其他昵稱. reply.target.missing=冇有回複 reply.target.self=你不能給自己發送私信 whisper.console=[] -> [] diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index c7f031af3..c8ce12e6e 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -22,14 +22,17 @@ dependencies { exclude("net.kyori", "adventure-api") exclude("net.kyori", "adventure-text-serializer-gson") exclude("net.kyori", "adventure-text-serializer-plain") - exclude("cloud.commandframework", "cloud-core") - exclude("cloud.commandframework", "cloud-services") - exclude("cloud.commandframework", "cloud-brigadier") + exclude("org.incendo", "cloud-core") + exclude("org.incendo", "cloud-services") + exclude("org.incendo", "cloud-brigadier") + exclude("org.incendo", "cloud-minecraft-signed-arguments") exclude("io.leangen.geantyref") } modImplementation(libs.cloudFabric) include(libs.cloudFabric) + implementation(libs.cloudSigned) + include(libs.cloudSigned) modImplementation(libs.fabricPermissionsApi) modImplementation(libs.adventurePlatformFabric) @@ -52,7 +55,7 @@ carbonPlatform { tasks { shadowJar { configurations = listOf(shade) - relocateDependency("cloud.commandframework.minecraft.extras") + relocateDependency("org.incendo.cloud.minecraft.extras") standardRuntimeRelocations() relocateGuice() relocateDependency("org.checkerframework") diff --git a/fabric/src/main/java/net/draycia/carbon/fabric/CarbonChatFabricModule.java b/fabric/src/main/java/net/draycia/carbon/fabric/CarbonChatFabricModule.java index 452345a68..a8c65852e 100644 --- a/fabric/src/main/java/net/draycia/carbon/fabric/CarbonChatFabricModule.java +++ b/fabric/src/main/java/net/draycia/carbon/fabric/CarbonChatFabricModule.java @@ -19,8 +19,6 @@ */ package net.draycia.carbon.fabric; -import cloud.commandframework.CommandManager; -import cloud.commandframework.fabric.FabricServerCommandManager; import com.google.inject.Provider; import com.google.inject.Provides; import com.google.inject.Singleton; @@ -35,6 +33,7 @@ import net.draycia.carbon.common.CarbonPlatformModule; import net.draycia.carbon.common.DataDirectory; import net.draycia.carbon.common.PlatformScheduler; +import net.draycia.carbon.common.RawChat; import net.draycia.carbon.common.command.CommandSettings; import net.draycia.carbon.common.command.Commander; import net.draycia.carbon.common.command.ExecutionCoordinatorHolder; @@ -46,6 +45,7 @@ import net.draycia.carbon.common.util.CloudUtils; import net.draycia.carbon.fabric.command.FabricCommander; import net.draycia.carbon.fabric.command.FabricPlayerCommander; +import net.draycia.carbon.fabric.listeners.FabricChatHandler; import net.draycia.carbon.fabric.users.CarbonPlayerFabric; import net.draycia.carbon.fabric.users.FabricProfileResolver; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @@ -58,6 +58,9 @@ import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.SenderMapper; +import org.incendo.cloud.fabric.FabricServerCommandManager; @DefaultQualifier(NonNull.class) public final class CarbonChatFabricModule extends CarbonPlatformModule { @@ -94,18 +97,18 @@ public CommandManager commandManager( final FabricServerCommandManager commandManager = new FabricServerCommandManager<>( executionCoordinatorHolder.executionCoordinator(), - commandSourceStack -> { - if (commandSourceStack.getEntity() instanceof ServerPlayer) { - return new FabricPlayerCommander(carbonChat.get(), commandSourceStack); - } - return FabricCommander.from(commandSourceStack); - }, - commander -> ((FabricCommander) commander).commandSourceStack() + SenderMapper.create( + commandSourceStack -> { + if (commandSourceStack.getEntity() instanceof ServerPlayer) { + return new FabricPlayerCommander(carbonChat.get(), commandSourceStack); + } + return FabricCommander.from(commandSourceStack); + }, + commander -> ((FabricCommander) commander).commandSourceStack() + ) ); - CloudUtils.decorateCommandManager(commandManager, carbonMessages); - - commandManager.brigadierManager().setNativeNumberSuggestions(false); + CloudUtils.decorateCommandManager(commandManager, carbonMessages, this.logger); return commandManager; } @@ -123,6 +126,7 @@ protected void configurePlatform() { this.bind(PlatformScheduler.class).to(FabricScheduler.class); this.install(PlatformUserManager.PlayerFactory.moduleFor(CarbonPlayerFabric.class)); this.bind(CarbonMessageRenderer.class).to(FabricMessageRenderer.class); + this.bind(Key.class).annotatedWith(RawChat.class).toProvider(() -> FabricChatHandler.CHAT_TYPE_KEY); } } diff --git a/fabric/src/main/java/net/draycia/carbon/fabric/FabricMessageRenderer.java b/fabric/src/main/java/net/draycia/carbon/fabric/FabricMessageRenderer.java index 7fd7d1f0e..e3f9742c6 100644 --- a/fabric/src/main/java/net/draycia/carbon/fabric/FabricMessageRenderer.java +++ b/fabric/src/main/java/net/draycia/carbon/fabric/FabricMessageRenderer.java @@ -70,7 +70,7 @@ public Component render( if (sourced.sender() instanceof CarbonPlayerFabric sender) { tagResolver.resolver(MiniPlaceholders.getAudiencePlaceholders(sender)); if (sourced.recipient() instanceof CarbonPlayerFabric recipient && recipient.online()) { - tagResolver.resolver(MiniPlaceholders.getRelationalPlaceholders(sender, recipient)); + tagResolver.resolver(MiniPlaceholders.getRelationalPlaceholders(recipient, sender)); } } else if (sourced.sender() instanceof ConsoleCarbonPlayer console) { // I don't know if this will ever actually resolve anything, or if anything supports console audience diff --git a/fabric/src/main/java/net/draycia/carbon/fabric/listeners/FabricChatHandler.java b/fabric/src/main/java/net/draycia/carbon/fabric/listeners/FabricChatHandler.java index 8ee22463f..8ac597054 100644 --- a/fabric/src/main/java/net/draycia/carbon/fabric/listeners/FabricChatHandler.java +++ b/fabric/src/main/java/net/draycia/carbon/fabric/listeners/FabricChatHandler.java @@ -47,7 +47,7 @@ public class FabricChatHandler extends ChatListenerInternal implements ServerMessageEvents.AllowChatMessage { - private static final ResourceLocation CHAT_TYPE_KEY = new ResourceLocation("carbonchat", "chat"); + public static final ResourceLocation CHAT_TYPE_KEY = new ResourceLocation("carbonchat", "chat"); private final CarbonChatFabric carbonChat; private @MonotonicNonNull ResourceKey chatTypeResourceKey; diff --git a/fabric/src/main/java/net/draycia/carbon/fabric/mixin/PlayerListMixin.java b/fabric/src/main/java/net/draycia/carbon/fabric/mixin/PlayerListMixin.java index e9517dafb..d3a1a2163 100644 --- a/fabric/src/main/java/net/draycia/carbon/fabric/mixin/PlayerListMixin.java +++ b/fabric/src/main/java/net/draycia/carbon/fabric/mixin/PlayerListMixin.java @@ -19,7 +19,6 @@ */ package net.draycia.carbon.fabric.mixin; -import cloud.commandframework.types.tuples.Pair; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import net.draycia.carbon.fabric.callback.PlayerStatusMessageEvents; @@ -31,6 +30,7 @@ import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.players.PlayerList; import org.checkerframework.checker.nullness.qual.Nullable; +import org.incendo.cloud.type.tuple.Pair; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -70,12 +70,12 @@ public void injectJoin(final Connection connection, final ServerPlayer serverPla final @Nullable Pair remove = this.joinMsg.remove(Thread.currentThread()); if (remove != null) { final PlayerStatusMessageEvents.MessageEvent event = PlayerStatusMessageEvents.MessageEvent.of( - serverPlayer, remove.getFirst().asComponent() + serverPlayer, remove.first().asComponent() ); PlayerStatusMessageEvents.JOIN_MESSAGE.invoker().onMessage(event); final net.kyori.adventure.text.@Nullable Component message = event.message(); if (message != null) { - this.broadcastSystemMessage(FabricServerAudiences.of(this.server).toNative(message), remove.getSecond()); + this.broadcastSystemMessage(FabricServerAudiences.of(this.server).toNative(message), remove.second()); } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e68cd69ef..61b3d662f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ sponge-gradle = { id = "org.spongepowered.gradle.plugin", version = "2.2.0" } hangar-publish = { id = "io.papermc.hangar-publish-plugin", version = "0.1.2" } indra-publishing-sonatype = { id = "net.kyori.indra.publishing.sonatype", version.ref = "indra" } -javadoc-links = { id = "org.incendo.cloud-build-logic.javadoc-links", version = "0.0.13" } +javadoc-links = { id = "org.incendo.cloud-build-logic.javadoc-links", version = "0.0.15" } [versions] indra = "3.1.3" @@ -10,13 +10,15 @@ shadow = "8.1.1" pluginYml = "0.5.3" mod-publish-plugin = "0.5.1" gremlin = "0.0.6" -runTask = "2.2.3" +runTask = "2.3.0" -adventure = "4.15.0" -cloud = "1.8.4" -cloudSponge = "1.8.0-SNAPSHOT" +adventure = "4.16.0" +cloud = "2.0.0-beta.5" +cloudMinecraft = "2.0.0-beta.6" +cloudModded = "2.0.0-beta.5" +cloudSponge = "2.0.0-beta.6" configurate = "4.2.0-SNAPSHOT" -checkerQual = "3.42.0" +checkerQual = "3.43.0" stylecheck = "0.2.1" bstats = "3.0.2" paperApi = "1.19.4-R0.1-SNAPSHOT" @@ -28,31 +30,31 @@ kyoriMoonshine = "2.0.4" guice = "7.0.0" velocityApi = "3.3.0-SNAPSHOT" minecraft = "1.20.4" -fabricLoader = "0.15.4" -fabricApi = "0.94.0+1.20.4" -fabricPermissionsApi = "0.2-SNAPSHOT" -adventurePlatformFabric = "5.11.0" +fabricLoader = "0.15.11" +fabricApi = "0.97.1+1.20.4" +fabricPermissionsApi = "0.3.1" +adventurePlatformFabric = "5.12.0" luckPermsApi = "5.4" essentialsx = "2.20.1" -discordsrv = "1.26.0" -placeholderapi = "2.11.5" +discordsrv = "1.27.0" +placeholderapi = "2.11.6" miniplaceholders = "2.2.3" -jdbi = "3.45.0" +jdbi = "3.45.1" hikari = "5.1.0" -mysql = "8.3.0" -flyway = "10.9.1" +mysql = "8.4.0" +flyway = "10.12.0" caffeine = "3.1.8" mariadb = "3.3.3" messenger = "1.1.0-SNAPSHOT" -zstdjni = "1.5.5-11" +zstdjni = "1.5.6-3" jedis = "5.1.2" -postgresql = "42.7.2" -rabbitmq = "5.20.0" -nats = "2.17.3" +postgresql = "42.7.3" +rabbitmq = "5.21.0" +nats = "2.17.6" h2 = "2.2.224" -towny = "0.100.0.9" -mcmmo = "2.1.225" -fuuid = "1.6.9.5-U0.6.33" +towny = "0.100.3.0" +mcmmo = "2.1.227" +fuuid = "1.6.9.5-U0.6.35" # synced with version used by lowest supported mc (currently 1.20.4 on paper) gson = "2.10.1" @@ -64,7 +66,6 @@ netty = "4.1.97.Final" indraCommon = { group = "net.kyori", name = "indra-common", version.ref = "indra" } indraLicenseHeader = { group = "net.kyori", name = "indra-licenser-spotless", version.ref = "indra" } shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" } -pluginYml = { group = "net.minecrell", name = "plugin-yml", version.ref = "pluginYml" } mod-publish-plugin = { module = "me.modmuss50:mod-publish-plugin", version.ref = "mod-publish-plugin" } gremlin-gradle = { group = "xyz.jpenilla", name = "gremlin-gradle", version.ref = "gremlin" } run-task = { module = "xyz.jpenilla:run-task", version.ref = "runTask" } @@ -84,16 +85,23 @@ registry = { group = "com.seiama", name = "registry", version.ref = "registry" } kyoriMoonshine = { group = "net.kyori.moonshine", name = "moonshine", version.ref = "kyoriMoonshine" } kyoriMoonshineCore = { group = "net.kyori.moonshine", name = "moonshine-core", version.ref = "kyoriMoonshine" } kyoriMoonshineStandard = { group = "net.kyori.moonshine", name = "moonshine-standard", version.ref = "kyoriMoonshine" } -cloudBom = { group = "cloud.commandframework", name = "cloud-bom", version.ref = "cloud" } -cloudCore = { group = "cloud.commandframework", name = "cloud-core" } -cloudMinecraftExtras = { group = "cloud.commandframework", name = "cloud-minecraft-extras" } -cloudPaper = { group = "cloud.commandframework", name = "cloud-paper" } -cloudSponge = { group = "cloud.commandframework", name = "cloud-sponge", version.ref = "cloudSponge" } -cloudVelocity = { group = "cloud.commandframework", name = "cloud-velocity" } -cloudFabric = { group = "cloud.commandframework", name = "cloud-fabric", version.ref = "cloud" } + +cloudBom = { module = "org.incendo:cloud-bom", version.ref = "cloud" } +cloudCore = { group = "org.incendo", name = "cloud-core", version.ref = "cloud" } +brigadier = "com.mojang:brigadier:1.0.18" +cloudMinecraftBom = { module = "org.incendo:cloud-minecraft-bom", version.ref = "cloudMinecraft" } +cloudMinecraftExtras = { group = "org.incendo", name = "cloud-minecraft-extras", version.ref = "cloudMinecraft" } +cloudPaper = { group = "org.incendo", name = "cloud-paper", version.ref = "cloudMinecraft" } +cloudSigned = { group = "org.incendo", name = "cloud-minecraft-signed-arguments", version.ref = "cloudMinecraft" } +cloudPaperSigned = { group = "org.incendo", name = "cloud-paper-signed-arguments", version.ref = "cloudMinecraft" } +cloudSponge = { group = "org.incendo", name = "cloud-sponge", version.ref = "cloudSponge" } +cloudVelocity = { group = "org.incendo", name = "cloud-velocity", version.ref = "cloudMinecraft" } +cloudFabric = { group = "org.incendo", name = "cloud-fabric", version.ref = "cloudModded"} + configurateCore = { group = "org.spongepowered", name = "configurate-core", version.ref = "configurate" } configurateHocon = { group = "org.spongepowered", name = "configurate-hocon", version.ref = "configurate" } configurateYaml = { group = "org.spongepowered", name = "configurate-yaml", version.ref = "configurate" } + checkerQual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerQual" } stylecheck = { group = "ca.stellardrift", name = "stylecheck", version.ref = "stylecheck" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917..e6441136f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22ce5..b82aa23a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/paper/build.gradle.kts b/paper/build.gradle.kts index ee4a58a40..a28cf0c2c 100644 --- a/paper/build.gradle.kts +++ b/paper/build.gradle.kts @@ -1,9 +1,11 @@ +import xyz.jpenilla.resourcefactory.paper.PaperPluginYaml.Load import xyz.jpenilla.runpaper.task.RunServer plugins { id("carbon.shadow-platform") - id("net.minecrell.plugin-yml.bukkit") - id("paper-plugin-yml") + id("xyz.jpenilla.resource-factory") version "1.1.1" + id("xyz.jpenilla.resource-factory-paper-convention") version "1.1.1" + id("xyz.jpenilla.resource-factory-bukkit-convention") version "1.1.1" id("xyz.jpenilla.run-paper") id("carbon.permissions") id("carbon.configurable-plugins") @@ -18,6 +20,7 @@ dependencies { // Commands implementation(libs.cloudPaper) + implementation(libs.cloudPaperSigned) // Misc implementation(libs.bstatsBukkit) @@ -48,12 +51,14 @@ tasks { shadowJar { relocateDependency("io.papermc.papertrail") relocateDependency("io.leangen.geantyref") + relocateDependency("xyz.jpenilla.reflectionremapper") + relocateDependency("net.fabricmc.mappingio") relocateCloud() } withType(RunServer::class).configureEach { version.set(libs.versions.minecraft) downloadPlugins { - url("https://download.luckperms.net/1533/bukkit/loader/LuckPerms-Bukkit-5.4.120.jar") + url("https://download.luckperms.net/1543/bukkit/loader/LuckPerms-Bukkit-5.4.130.jar") github("MiniPlaceholders", "MiniPlaceholders", libs.versions.miniplaceholders.get(), "MiniPlaceholders-Paper-${libs.versions.miniplaceholders.get()}.jar") github("MiniPlaceholders", "PlaceholderAPI-Expansion", "1.2.0", "PlaceholderAPI-Expansion-1.2.0.jar") hangar("PlaceholderAPI", libs.versions.placeholderapi.get()) @@ -67,31 +72,31 @@ tasks { runPaper.folia.registerTask() -paper { +paperPluginYaml { name = rootProject.name - version = project.version as String loader = "net.draycia.carbon.paper.CarbonPaperLoader" main = "net.draycia.carbon.paper.CarbonPaperBootstrap" - apiVersion = "1.19" + apiVersion = "1.20" authors = listOf("Draycia", "jmp") website = GITHUB_REPO_URL foliaSupported = true - dependency("LuckPerms", PaperPluginDescription.Load.BEFORE, true) - dependency("PlaceholderAPI", PaperPluginDescription.Load.BEFORE, false) - dependency("EssentialsDiscord", PaperPluginDescription.Load.BEFORE, false) - dependency("DiscordSRV", PaperPluginDescription.Load.BEFORE, false) - dependency("MiniPlaceholders", PaperPluginDescription.Load.BEFORE, false) - - // Integrations - dependency("Towny", PaperPluginDescription.Load.BEFORE, false) - dependency("mcMMO", PaperPluginDescription.Load.BEFORE, false) - dependency("Factions", PaperPluginDescription.Load.BEFORE, false) + dependencies { + server("LuckPerms", Load.BEFORE, true) + server("PlaceholderAPI", Load.BEFORE, false) + server("EssentialsDiscord", Load.BEFORE, false) + server("DiscordSRV", Load.BEFORE, false) + server("MiniPlaceholders", Load.BEFORE, false) + + // Integrations + server("Towny", Load.BEFORE, false) + server("mcMMO", Load.BEFORE, false) + server("Factions", Load.BEFORE, false) + } } -bukkit { +bukkitPluginYaml { name = rootProject.name - version = project.version as String main = "carbonchat.libs.io.papermc.papertrail.RequiresPaperPlugins" apiVersion = "1.20" authors = listOf("Draycia", "jmp") @@ -99,10 +104,10 @@ bukkit { } carbonPermission.permissions.get().forEach { - setOf(bukkit.permissions, paper.permissions).forEach { container -> + setOf(bukkitPluginYaml.permissions, paperPluginYaml.permissions).forEach { container -> container.register(it.string) { description = it.description - childrenMap = it.children + it.children?.let { children.putAll(it) } } } } diff --git a/paper/src/main/java/net/draycia/carbon/paper/CarbonChatPaperModule.java b/paper/src/main/java/net/draycia/carbon/paper/CarbonChatPaperModule.java index 8610eea7e..2e6913780 100644 --- a/paper/src/main/java/net/draycia/carbon/paper/CarbonChatPaperModule.java +++ b/paper/src/main/java/net/draycia/carbon/paper/CarbonChatPaperModule.java @@ -19,9 +19,6 @@ */ package net.draycia.carbon.paper; -import cloud.commandframework.CommandManager; -import cloud.commandframework.brigadier.CloudBrigadierManager; -import cloud.commandframework.paper.PaperCommandManager; import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.multibindings.Multibinder; @@ -33,6 +30,7 @@ import net.draycia.carbon.common.CarbonPlatformModule; import net.draycia.carbon.common.DataDirectory; import net.draycia.carbon.common.PlatformScheduler; +import net.draycia.carbon.common.RawChat; import net.draycia.carbon.common.command.Commander; import net.draycia.carbon.common.command.ExecutionCoordinatorHolder; import net.draycia.carbon.common.integration.Integration; @@ -51,6 +49,7 @@ import net.draycia.carbon.paper.messages.PaperMessageRenderer; import net.draycia.carbon.paper.users.CarbonPlayerPaper; import net.draycia.carbon.paper.users.PaperProfileResolver; +import net.kyori.adventure.key.Key; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bukkit.Server; @@ -58,8 +57,10 @@ import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.SenderMapper; +import org.incendo.cloud.paper.PaperCommandManager; @DefaultQualifier(NonNull.class) public final class CarbonChatPaperModule extends CarbonPlatformModule { @@ -75,12 +76,10 @@ public final class CarbonChatPaperModule extends CarbonPlatformModule { @Singleton @SuppressWarnings("unused") public CommandManager commandManager(final UserManager userManager, final CarbonMessages messages, final ExecutionCoordinatorHolder executionCoordinatorHolder) { - final PaperCommandManager commandManager; - - try { - commandManager = new PaperCommandManager<>( - this.bootstrap, - executionCoordinatorHolder.executionCoordinator(), + final PaperCommandManager commandManager = new PaperCommandManager<>( + this.bootstrap, + executionCoordinatorHolder.executionCoordinator(), + SenderMapper.create( commandSender -> { if (commandSender instanceof Player player) { return new PaperPlayerCommander(userManager, player); @@ -88,23 +87,13 @@ public CommandManager commandManager(final UserManager userManager return PaperCommander.from(commandSender); }, commander -> ((PaperCommander) commander).commandSender() - ); - } catch (final Exception ex) { - throw new RuntimeException("Failed to initialize command manager.", ex); - } + ) + ); - CloudUtils.decorateCommandManager(commandManager, messages); + CloudUtils.decorateCommandManager(commandManager, messages, this.logger); - commandManager.registerAsynchronousCompletions(); commandManager.registerBrigadier(); - final @Nullable CloudBrigadierManager brigadierManager = - commandManager.brigadierManager(); - - if (brigadierManager != null) { - brigadierManager.setNativeNumberSuggestions(false); - } - return commandManager; } @@ -122,6 +111,7 @@ protected void configurePlatform() { this.bind(PlatformScheduler.class).to(PaperScheduler.class); this.install(PlatformUserManager.PlayerFactory.moduleFor(CarbonPlayerPaper.class)); this.bind(CarbonMessageRenderer.class).to(PaperMessageRenderer.class); + this.bind(Key.class).annotatedWith(RawChat.class).toInstance(Key.key("paper:raw")); this.configureListeners(); } diff --git a/paper/src/main/java/net/draycia/carbon/paper/messages/PaperMessageRenderer.java b/paper/src/main/java/net/draycia/carbon/paper/messages/PaperMessageRenderer.java index 6a7025ce5..5f049b9e8 100644 --- a/paper/src/main/java/net/draycia/carbon/paper/messages/PaperMessageRenderer.java +++ b/paper/src/main/java/net/draycia/carbon/paper/messages/PaperMessageRenderer.java @@ -123,13 +123,13 @@ public Component render( if (MiniPlaceholdersExpansion.miniPlaceholdersLoaded()) { tagResolver.resolver(MiniPlaceholders.getRelationalPlaceholders( - senderBukkitPlayer, - recipientBukkitPlayer + recipientBukkitPlayer, + senderBukkitPlayer )); } if (this.hasPlaceholderAPI()) { - return this.placeholderApiProcessor.get().parseRelational(senderBukkitPlayer, - recipientBukkitPlayer, placeholderResolvedMessage, tagResolver.build()); + return this.placeholderApiProcessor.get().parseRelational(recipientBukkitPlayer, + senderBukkitPlayer, placeholderResolvedMessage, tagResolver.build()); } return this.miniMessage.deserialize(placeholderResolvedMessage, tagResolver.build()); diff --git a/paper/src/main/java/net/draycia/carbon/paper/messages/PlaceholderAPIMiniMessageParser.java b/paper/src/main/java/net/draycia/carbon/paper/messages/PlaceholderAPIMiniMessageParser.java index de0bae9da..880dc2b42 100644 --- a/paper/src/main/java/net/draycia/carbon/paper/messages/PlaceholderAPIMiniMessageParser.java +++ b/paper/src/main/java/net/draycia/carbon/paper/messages/PlaceholderAPIMiniMessageParser.java @@ -70,17 +70,17 @@ public Component parse(final OfflinePlayer player, final String input) { return this.parse(player, input, TagResolver.empty()); } - public Component parseRelational(final Player one, final Player two, final String input, final TagResolver tagResolver) { + public Component parseRelational(final Player recipient, final Player sender, final String input, final TagResolver tagResolver) { return this.parse( PlaceholderAPI.getPlaceholderPattern(), - match -> PlaceholderAPI.setPlaceholders(one, PlaceholderAPI.setRelationalPlaceholders(one, two, match)), + match -> PlaceholderAPI.setPlaceholders(sender, PlaceholderAPI.setRelationalPlaceholders(recipient, sender, match)), input, tagResolver ); } - public Component parseRelational(final Player one, final Player two, final String input) { - return this.parseRelational(one, two, input, TagResolver.empty()); + public Component parseRelational(final Player recipient, final Player sender, final String input) { + return this.parseRelational(recipient, sender, input, TagResolver.empty()); } private Component parse( diff --git a/paper/src/main/java/net/draycia/carbon/paper/users/CarbonPlayerPaper.java b/paper/src/main/java/net/draycia/carbon/paper/users/CarbonPlayerPaper.java index 117d9c282..acfc4e0c7 100644 --- a/paper/src/main/java/net/draycia/carbon/paper/users/CarbonPlayerPaper.java +++ b/paper/src/main/java/net/draycia/carbon/paper/users/CarbonPlayerPaper.java @@ -116,7 +116,10 @@ public void nickname(final @Nullable Component nickname) { private Consumer applyDisplayNameToBukkit(final @Nullable Component displayName) { return bukkit -> this.carbonPlayerCommon.schedule(() -> { bukkit.displayName(displayName); - bukkit.playerListName(displayName); + + if (this.carbonPlayerCommon.configManager().primaryConfig().nickname().updateTabList()) { + bukkit.playerListName(displayName); + } }); } diff --git a/settings.gradle.kts b/settings.gradle.kts index af9921ad8..b995ad40c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,7 +7,7 @@ dependencyResolutionManagement { mavenContent { snapshotsOnly() includeModuleByRegex("de\\.hexaoxi", "messenger-.*") - includeModule("cloud.commandframework", "cloud-sponge") + includeModule("org.incendo", "cloud-sponge") } } maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") { @@ -77,7 +77,7 @@ pluginManagement { plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" - id("quiet-fabric-loom") version "1.5-SNAPSHOT" + id("quiet-fabric-loom") version "1.6.281" } rootProject.name = "CarbonChat" diff --git a/sponge/src/main/java/net/draycia/carbon/sponge/CarbonChatSpongeModule.java b/sponge/src/main/java/net/draycia/carbon/sponge/CarbonChatSpongeModule.java index 5af4cf2db..efe48370a 100644 --- a/sponge/src/main/java/net/draycia/carbon/sponge/CarbonChatSpongeModule.java +++ b/sponge/src/main/java/net/draycia/carbon/sponge/CarbonChatSpongeModule.java @@ -19,10 +19,10 @@ */ package net.draycia.carbon.sponge; -import cloud.commandframework.CommandManager; -import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator; -import cloud.commandframework.sponge.SpongeCommandManager; -import cloud.commandframework.sponge.argument.SinglePlayerSelectorArgument; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.AsynchronousCommandExecutionCoordinator; +import org.incendo.cloud.sponge.SpongeCommandManager; +import org.incendo.cloud.sponge.argument.SinglePlayerSelectorArgument; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Provides; diff --git a/velocity/src/main/java/net/draycia/carbon/velocity/CarbonChatVelocityModule.java b/velocity/src/main/java/net/draycia/carbon/velocity/CarbonChatVelocityModule.java index 02ecd82e9..f7b4810ad 100644 --- a/velocity/src/main/java/net/draycia/carbon/velocity/CarbonChatVelocityModule.java +++ b/velocity/src/main/java/net/draycia/carbon/velocity/CarbonChatVelocityModule.java @@ -19,8 +19,6 @@ */ package net.draycia.carbon.velocity; -import cloud.commandframework.CommandManager; -import cloud.commandframework.velocity.VelocityCommandManager; import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.TypeLiteral; @@ -37,6 +35,7 @@ import net.draycia.carbon.common.CarbonPlatformModule; import net.draycia.carbon.common.DataDirectory; import net.draycia.carbon.common.PlatformScheduler; +import net.draycia.carbon.common.RawChat; import net.draycia.carbon.common.command.Commander; import net.draycia.carbon.common.command.ExecutionCoordinatorHolder; import net.draycia.carbon.common.messages.CarbonMessageRenderer; @@ -52,10 +51,14 @@ import net.draycia.carbon.velocity.listeners.VelocityPlayerLeaveListener; import net.draycia.carbon.velocity.users.CarbonPlayerVelocity; import net.draycia.carbon.velocity.users.VelocityProfileResolver; +import net.kyori.adventure.key.Key; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.SenderMapper; +import org.incendo.cloud.velocity.VelocityCommandManager; @DefaultQualifier(NonNull.class) public final class CarbonChatVelocityModule extends CarbonPlatformModule { @@ -89,19 +92,19 @@ public CommandManager createCommandManager( this.pluginContainer, this.proxyServer, executionCoordinatorHolder.executionCoordinator(), - commandSender -> { - if (commandSender instanceof Player player) { - return new VelocityPlayerCommander(userManager, player); - } + SenderMapper.create( + commandSender -> { + if (commandSender instanceof Player player) { + return new VelocityPlayerCommander(userManager, player); + } - return VelocityCommander.from(commandSender); - }, - commander -> ((VelocityCommander) commander).commandSource() + return VelocityCommander.from(commandSender); + }, + commander -> ((VelocityCommander) commander).commandSource() + ) ); - CloudUtils.decorateCommandManager(commandManager, messages); - final var brigadierManager = commandManager.brigadierManager(); - brigadierManager.setNativeNumberSuggestions(false); + CloudUtils.decorateCommandManager(commandManager, messages, this.logger); return commandManager; } @@ -123,6 +126,7 @@ protected void configurePlatform() { this.bind(PlatformScheduler.class).to(PlatformScheduler.RunImmediately.class); this.install(PlatformUserManager.PlayerFactory.moduleFor(CarbonPlayerVelocity.class)); this.bind(CarbonMessageRenderer.class).to(VelocityMessageRenderer.class); + this.bind(Key.class).annotatedWith(RawChat.class).toInstance(Key.key("unused:unused")); this.configureListeners(); } diff --git a/velocity/src/main/java/net/draycia/carbon/velocity/VelocityMessageRenderer.java b/velocity/src/main/java/net/draycia/carbon/velocity/VelocityMessageRenderer.java index 1314d81c8..5e0ab995e 100644 --- a/velocity/src/main/java/net/draycia/carbon/velocity/VelocityMessageRenderer.java +++ b/velocity/src/main/java/net/draycia/carbon/velocity/VelocityMessageRenderer.java @@ -72,7 +72,7 @@ public Component render( if (sourced.sender() instanceof CarbonPlayerVelocity sender) { tagResolver.resolver(MiniPlaceholders.getAudiencePlaceholders(sender)); if (sourced.recipient() instanceof CarbonPlayerVelocity recipient) { - tagResolver.resolver(MiniPlaceholders.getRelationalGlobalPlaceholders(sender, recipient)); + tagResolver.resolver(MiniPlaceholders.getRelationalGlobalPlaceholders(recipient, sender)); } } else if (sourced.sender() instanceof ConsoleCarbonPlayer console) { // I don't know if this will ever actually resolve anything, or if anything supports console audience