From 30303d5f16bf10212bcbc5a52f2fc7bf50b068db Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 16 Jan 2022 15:09:53 -0600 Subject: [PATCH] Implement support for adding Geyser subcommands --- api/geyser/pom.xml | 14 +- .../org/geysermc/geyser/api/GeyserApi.java | 8 + .../geysermc/geyser/api/command/Command.java | 124 +++++++++ .../geyser/api/command/CommandExecutor.java | 44 +++ .../geyser/api/command/CommandManager.java | 67 +++++ .../geyser/api/command/CommandSource.java | 46 ++-- .../api/connection/GeyserConnection.java | 3 +- .../geysermc/geyser/api/event/EventBus.java | 20 +- .../geyser/api/event/EventSubscription.java | 2 +- .../geyser/api/event/ExtensionEventBus.java | 61 +++++ .../api/event/connection/ConnectionEvent.java | 47 ++++ .../downstream/ServerDefineCommandsEvent.java | 81 ++++++ .../lifecycle/GeyserDefineCommandsEvent.java | 42 +++ .../geyser/api/extension/Extension.java | 10 + .../geyser/api/extension/ExtensionLoader.java | 10 + .../bungeecord/GeyserBungeePlugin.java | 5 +- ...ndSender.java => BungeeCommandSource.java} | 10 +- .../command/GeyserBungeeCommandExecutor.java | 16 +- .../command/GeyserBungeeCommandManager.java | 6 +- .../platform/spigot/GeyserSpigotPlugin.java | 9 +- .../command/GeyserSpigotCommandExecutor.java | 14 +- .../command/GeyserSpigotCommandManager.java | 6 +- ...ndSender.java => SpigotCommandSource.java} | 8 +- .../platform/sponge/GeyserSpongePlugin.java | 5 +- .../command/GeyserSpongeCommandExecutor.java | 12 +- .../command/GeyserSpongeCommandManager.java | 6 +- ...ndSender.java => SpongeCommandSource.java} | 4 +- .../standalone/GeyserStandaloneBootstrap.java | 11 +- .../standalone/GeyserStandaloneLogger.java | 6 +- ...va => GeyserStandaloneCommandManager.java} | 8 +- .../standalone/gui/GeyserStandaloneGUI.java | 28 +- .../velocity/GeyserVelocityPlugin.java | 5 +- .../GeyserVelocityCommandExecutor.java | 16 +- .../command/GeyserVelocityCommandManager.java | 6 +- ...Sender.java => VelocityCommandSource.java} | 10 +- .../network/session/GeyserSession.java | 2 +- .../org/geysermc/geyser/GeyserBootstrap.java | 4 +- .../java/org/geysermc/geyser/GeyserImpl.java | 14 +- .../geyser/command/CommandManager.java | 122 --------- .../geyser/command/GeyserCommand.java | 28 +- ...ecutor.java => GeyserCommandExecutor.java} | 18 +- .../geyser/command/GeyserCommandManager.java | 256 ++++++++++++++++++ .../geyser/command/GeyserCommandSource.java | 43 +++ .../defaults/AdvancedTooltipsCommand.java | 6 +- .../command/defaults/AdvancementsCommand.java | 4 +- .../geyser/command/defaults/DumpCommand.java | 26 +- .../geyser/command/defaults/HelpCommand.java | 17 +- .../geyser/command/defaults/ListCommand.java | 6 +- .../command/defaults/OffhandCommand.java | 4 +- .../command/defaults/ReloadCommand.java | 6 +- .../command/defaults/SettingsCommand.java | 4 +- .../command/defaults/StatisticsCommand.java | 4 +- .../geyser/command/defaults/StopCommand.java | 6 +- .../command/defaults/VersionCommand.java | 14 +- .../geysermc/geyser/entity/type/Entity.java | 2 +- .../geysermc/geyser/event/GeyserEventBus.java | 13 +- .../extension/GeyserExtensionContainer.java | 2 + .../extension/GeyserExtensionLoader.java | 14 +- .../extension/GeyserExtensionManager.java | 7 +- .../event/GeyserExtensionEventBus.java | 87 ++++++ .../updater/AnvilInventoryUpdater.java | 4 +- .../geyser/network/UpstreamPacketHandler.java | 4 +- .../geyser/session/GeyserSession.java | 12 +- .../geyser/session/SessionManager.java | 2 +- .../session/cache/AdvancementsCache.java | 8 +- .../geyser/session/cache/BossBar.java | 4 +- .../inventory/item/ItemTranslator.java | 6 +- .../item/nbt/AxolotlBucketTranslator.java | 2 +- .../item/nbt/BasicItemTranslator.java | 2 +- .../item/nbt/PlayerHeadTranslator.java | 2 +- .../nbt/TropicalFishBucketTranslator.java | 8 +- .../BedrockCommandRequestTranslator.java | 4 +- .../bedrock/BedrockFilterTextTranslator.java | 4 +- .../protocol/java/JavaChatTranslator.java | 2 +- .../protocol/java/JavaCommandsTranslator.java | 16 +- .../java/JavaDisconnectTranslator.java | 2 +- .../java/JavaLoginDisconnectTranslator.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 2 +- .../JavaUpdateAdvancementsTranslator.java | 4 +- .../inventory/JavaOpenScreenTranslator.java | 4 +- .../java/level/JavaGameEventTranslator.java | 2 +- .../java/level/JavaLevelEventTranslator.java | 2 +- .../JavaSetPlayerTeamTranslator.java | 8 +- .../title/JavaSetActionBarTextTranslator.java | 2 +- .../title/JavaSetSubtitleTextTranslator.java | 2 +- .../title/JavaSetTitleTextTranslator.java | 2 +- .../translator/text/MessageTranslator.java | 2 +- .../geyser/util/LoginEncryptionUtils.java | 12 +- .../geysermc/geyser/util/SettingsUtils.java | 2 +- .../geysermc/geyser/util/StatisticsUtils.java | 2 +- 90 files changed, 1207 insertions(+), 402 deletions(-) create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java rename core/src/main/java/org/geysermc/geyser/command/CommandSender.java => api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java (66%) create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java rename bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/{BungeeCommandSender.java => BungeeCommandSource.java} (89%) rename bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/{SpigotCommandSender.java => SpigotCommandSource.java} (95%) rename bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/{SpongeCommandSender.java => SpongeCommandSource.java} (94%) rename bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/{GeyserCommandManager.java => GeyserStandaloneCommandManager.java} (85%) rename bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/{VelocityCommandSender.java => VelocityCommandSource.java} (90%) delete mode 100644 core/src/main/java/org/geysermc/geyser/command/CommandManager.java rename core/src/main/java/org/geysermc/geyser/command/{CommandExecutor.java => GeyserCommandExecutor.java} (85%) create mode 100644 core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 88f1cafdc..b2f448589 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -26,6 +26,12 @@ 3.19.0 provided + + net.kyori + event-api + 3.0.0 + provided + net.kyori adventure-api @@ -33,10 +39,10 @@ compile - net.kyori - event-api - 3.0.0 - provided + org.yaml + snakeyaml + 1.27 + compile org.geysermc diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java index dbdee8b4e..2bddc9ef5 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; import org.geysermc.api.GeyserApiBase; +import org.geysermc.geyser.api.command.CommandManager; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.extension.ExtensionManager; @@ -89,6 +90,13 @@ public interface GeyserApi extends GeyserApiBase { */ ExtensionManager extensionManager(); + /** + * Gets the {@link CommandManager}. + * + * @return the command manager + */ + CommandManager commandManager(); + /** * Gets the {@link EventBus} for handling * Geyser events. diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java new file mode 100644 index 000000000..2c48473c6 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.command; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.GeyserApi; + +import java.util.Collections; +import java.util.List; + +/** + * Represents a command. + */ +public interface Command { + + /** + * Gets the command name. + * + * @return the command name + */ + @NonNull + String name(); + + /** + * Gets the command description. + * + * @return the command description + */ + @NonNull + String description(); + + /** + * Gets the permission node associated with + * this command. + * + * @return the permission node for this command + */ + @NonNull + String permission(); + + /** + * Gets the aliases for this command. + * + * @return the aliases for this command + */ + @NonNull + List aliases(); + + /** + * Gets if this command is executable on console. + * + * @return if this command is executable on console + */ + boolean isExecutableOnConsole(); + + /** + * Gets the subcommands associated with this + * command. Mainly used within the Geyser Standalone + * GUI to know what subcommands are supported. + * + * @return the subcommands associated with this command + */ + @NonNull + default List subCommands() { + return Collections.emptyList(); + } + + /** + * Used to send a deny message to Java players if this command can only be used by Bedrock players. + * + * @return true if this command can only be used by Bedrock players. + */ + default boolean isBedrockOnly() { + return false; + } + + static Command.Builder builder(Class sourceType) { + return GeyserApi.api().commandManager().provideBuilder(sourceType); + } + + interface Builder { + + Builder name(String name); + + Builder description(String description); + + Builder permission(String permission); + + Builder aliases(List aliases); + + Builder executableOnConsole(boolean executableOnConsole); + + Builder subCommands(List subCommands); + + Builder bedrockOnly(boolean bedrockOnly); + + Builder executor(CommandExecutor executor); + + Command build(); + } +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java new file mode 100644 index 000000000..d384d097c --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.command; + +/** + * Handles executing a command. + * + * @param the command source + */ +public interface CommandExecutor { + + /** + * Executes the given {@link Command} with the given + * {@link CommandSource}. + * + * @param source the command source + * @param command the command + * @param args the arguments + */ + void execute(T source, Command command, String[] args); +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java new file mode 100644 index 000000000..864ba71a4 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.command; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.Map; + +/** + * Manages Bedrock commands within Geyser. + */ +public abstract class CommandManager { + + /** + * Provides a {@link Command.Builder}. + * + * @param sourceType the command source type + * @param the type + * @return a command builder + */ + protected abstract Command.Builder provideBuilder(Class sourceType); + + /** + * Registers the given {@link Command}. + * + * @param command the command to register + */ + public abstract void register(@NonNull Command command); + + /** + * Unregisters the given {@link Command}. + * + * @param command the command to unregister + */ + public abstract void unregister(@NonNull Command command); + + /** + * Gets all the registered {@link Command}s. + * + * @return all the registered commands + */ + @NonNull + public abstract Map commands(); +} diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandSender.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java similarity index 66% rename from core/src/main/java/org/geysermc/geyser/command/CommandSender.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java index d9d1bcfbc..aabf0c4e8 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandSender.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java @@ -23,45 +23,57 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.command; - -import org.geysermc.geyser.text.GeyserLocale; +package org.geysermc.geyser.api.command; /** - * Implemented on top of any class that can send a command. - * For example, it wraps around Spigot's CommandSender class. + * Represents an instance capable of sending commands. */ -public interface CommandSender { +public interface CommandSource { + /** + * The name of the command source. + * + * @return the name of the command source + */ String name(); + /** + * Sends the given message to the command source + * + * @param message the message to send + */ + void sendMessage(String message); + + /** + * Sends the given messages to the command source + * + * @param messages the messages to send + */ default void sendMessage(String[] messages) { for (String message : messages) { sendMessage(message); } } - void sendMessage(String message); - /** - * @return true if the specified sender is from the console. + * If this source is the console. + * + * @return true if this source is the console */ boolean isConsole(); /** - * Returns the locale of the command sender. Defaults to the default locale at {@link GeyserLocale#getDefaultLocale()}. - * - * @return the locale of the command sender. + * Returns the locale of the command source. + * + * @return the locale of the command source. */ - default String getLocale() { - return GeyserLocale.getDefaultLocale(); - } + String locale(); /** - * Checks if the CommandSender has a permission + * Checks if this command source has the given permission * * @param permission The permission node to check - * @return true if the CommandSender has the requested permission, false if not + * @return true if this command source has a permission */ boolean hasPermission(String permission); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index 036c7c591..13fd60407 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -26,9 +26,10 @@ package org.geysermc.geyser.api.connection; import org.geysermc.api.connection.Connection; +import org.geysermc.geyser.api.command.CommandSource; /** * Represents a player connection used in Geyser. */ -public interface GeyserConnection extends Connection { +public interface GeyserConnection extends Connection, CommandSource { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java index a26e8c653..0352dcc9e 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java @@ -40,18 +40,7 @@ public interface EventBus { /** * Subscribes to the given event see {@link EventSubscription}. * - * @param eventClass the class of the event - * @param consumer the consumer for handling the event - * @param the event class - * @return the event subscription - */ - @NonNull - EventSubscription subscribe(@NonNull Class eventClass, @NonNull Consumer consumer); - - /** - * Subscribes to the given event see {@link EventSubscription}. - * - * The difference between this method and {@link #subscribe(Class, Consumer)} + * The difference between this method and {@link ExtensionEventBus#subscribe(Class, Consumer)} * is that this method takes in an extension parameter which allows for * the event to be unsubscribed upon extension disable and reloads. * @@ -79,6 +68,13 @@ public interface EventBus { */ void register(@NonNull Extension extension, @NonNull Object eventHolder); + /** + * Unregisters all events from a given {@link Extension}. + * + * @param extension the extension + */ + void unregisterAll(@NonNull Extension extension); + /** * Fires the given {@link Event}. * diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java index daa05ab21..2870c0ba6 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java @@ -63,7 +63,7 @@ public interface EventSubscription { * * @return the extension that owns this subscription */ - @Nullable + @NonNull Extension owner(); /** diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java new file mode 100644 index 000000000..db0209e5f --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.function.Consumer; + +/** + * An {@link EventBus} with additional methods that implicitly + * set the extension instance. + * + */ +public interface ExtensionEventBus extends EventBus { + + /** + * Subscribes to the given event see {@link EventSubscription}. + * + * @param eventClass the class of the event + * @param consumer the consumer for handling the event + * @param the event class + * @return the event subscription + */ + @NonNull + EventSubscription subscribe(@NonNull Class eventClass, @NonNull Consumer consumer); + + /** + * Registers events for the given listener. + * + * @param eventHolder the listener + */ + void register(@NonNull Object eventHolder); + + /** + * Unregisters all events for this extension. + */ + void unregisterAll(); +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java new file mode 100644 index 000000000..9dcb68908 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.connection; + +import lombok.RequiredArgsConstructor; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.event.Event; + +/** + * An event that contains a {@link GeyserConnection}. + */ +@RequiredArgsConstructor +public abstract class ConnectionEvent implements Event { + private final GeyserConnection connection; + + /** + * Gets the {@link GeyserConnection}. + * + * @return the connection + */ + public GeyserConnection connection() { + return this.connection; + } +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java new file mode 100644 index 000000000..559631acf --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.downstream; + +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.event.Cancellable; +import org.geysermc.geyser.api.event.connection.ConnectionEvent; + +import java.util.Set; + +/** + * Called when the downstream server defines the commands available on the server. + */ +public class ServerDefineCommandsEvent extends ConnectionEvent implements Cancellable { + private final Set commands; + private boolean cancelled; + + public ServerDefineCommandsEvent(GeyserConnection connection, Set commands) { + super(connection); + this.commands = commands; + } + + /** + * A mutable collection of the commands sent over. + * + * @return a mutable collection of the commands sent over + */ + public Set commands() { + return this.commands; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + public interface CommandInfo { + + /** + * Gets the name of the command. + * + * @return the name of the command + */ + String name(); + + /** + * Gets the description of the command. + * + * @return the description of the command + */ + String description(); + } +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java new file mode 100644 index 000000000..7f64a4622 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.lifecycle; + +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.command.CommandManager; +import org.geysermc.geyser.api.event.Event; + +import java.util.Map; + +/** + * Called when commands are defined within Geyser. + * + * @param commandManager the command manager + * @param commands a mutable list of the currently + * registered default commands + */ +public record GeyserDefineCommandsEvent(CommandManager commandManager, Map commands) implements Event { +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java index 097cabdc3..357165ffe 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.api.extension; import org.geysermc.api.GeyserApiBase; import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.event.ExtensionEventBus; import java.nio.file.Path; @@ -80,6 +81,15 @@ public interface Extension { return this.extensionLoader().dataFolder(this); } + /** + * Gets the {@link ExtensionEventBus}. + * + * @return the extension event bus + */ + default ExtensionEventBus eventBus() { + return this.extensionLoader().eventBus(this); + } + /** * Gets the {@link ExtensionManager}. * diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java index 651afd9eb..c84c37919 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.api.extension; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.event.ExtensionEventBus; import java.nio.file.Path; @@ -68,6 +69,15 @@ public abstract class ExtensionLoader { @NonNull protected abstract ExtensionDescription description(@NonNull Extension extension); + /** + * Gets the given {@link Extension}'s {@link ExtensionEventBus}. + * + * @param extension the extension + * @return the extension's event bus + */ + @NonNull + protected abstract ExtensionEventBus eventBus(@NonNull Extension extension); + /** * Gets the {@link ExtensionLogger} for the given {@link Extension}. * diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index f35082359..bb90e5000 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -30,7 +30,7 @@ import net.md_5.bungee.api.plugin.Plugin; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserBootstrap; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; @@ -126,6 +126,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserInjector.initializeLocalChannel(this); this.geyserCommandManager = new GeyserBungeeCommandManager(geyser); + this.geyserCommandManager.init(); if (geyserConfig.isLegacyPingPassthrough()) { this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser); @@ -157,7 +158,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } @Override - public CommandManager getGeyserCommandManager() { + public GeyserCommandManager getGeyserCommandManager() { return this.geyserCommandManager; } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java similarity index 89% rename from bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java rename to bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java index 05df8ba97..801fc8777 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java @@ -27,17 +27,17 @@ package org.geysermc.geyser.platform.bungeecord.command; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.GeyserLocale; -public class BungeeCommandSender implements CommandSender { +public class BungeeCommandSource implements GeyserCommandSource { private final net.md_5.bungee.api.CommandSender handle; - public BungeeCommandSender(net.md_5.bungee.api.CommandSender handle) { + public BungeeCommandSource(net.md_5.bungee.api.CommandSender handle) { this.handle = handle; // Ensure even Java players' languages are loaded - GeyserLocale.loadGeyserLocale(getLocale()); + GeyserLocale.loadGeyserLocale(this.locale()); } @Override @@ -56,7 +56,7 @@ public class BungeeCommandSender implements CommandSender { } @Override - public String getLocale() { + public String locale() { if (handle instanceof ProxiedPlayer player) { String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry(); return GeyserLocale.formatLocale(locale); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java index 5bb323aac..87e5f9e13 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java @@ -30,7 +30,7 @@ import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.TabExecutor; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandExecutor; +import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -39,30 +39,30 @@ import java.util.Arrays; import java.util.Collections; public class GeyserBungeeCommandExecutor extends Command implements TabExecutor { - private final CommandExecutor commandExecutor; + private final GeyserCommandExecutor commandExecutor; public GeyserBungeeCommandExecutor(GeyserImpl geyser) { super("geyser"); - this.commandExecutor = new CommandExecutor(geyser); + this.commandExecutor = new GeyserCommandExecutor(geyser); } @Override public void execute(CommandSender sender, String[] args) { - BungeeCommandSender commandSender = new BungeeCommandSender(sender); + BungeeCommandSource commandSender = new BungeeCommandSource(sender); GeyserSession session = this.commandExecutor.getGeyserSession(commandSender); if (args.length > 0) { GeyserCommand command = this.commandExecutor.getCommand(args[0]); if (command != null) { - if (!sender.hasPermission(command.getPermission())) { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale()); + if (!sender.hasPermission(command.permission())) { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.locale()); commandSender.sendMessage(ChatColor.RED + message); return; } if (command.isBedrockOnly() && session == null) { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.getLocale()); + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.locale()); commandSender.sendMessage(ChatColor.RED + message); return; @@ -77,7 +77,7 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor @Override public Iterable onTabComplete(CommandSender sender, String[] args) { if (args.length == 1) { - return commandExecutor.tabComplete(new BungeeCommandSender(sender)); + return commandExecutor.tabComplete(new BungeeCommandSource(sender)); } else { return Collections.emptyList(); } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java index 019544c28..e0fd7a4ac 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java @@ -26,16 +26,16 @@ package org.geysermc.geyser.platform.bungeecord.command; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; -public class GeyserBungeeCommandManager extends CommandManager { +public class GeyserBungeeCommandManager extends GeyserCommandManager { public GeyserBungeeCommandManager(GeyserImpl geyser) { super(geyser); } @Override - public String getDescription(String command) { + public String description(String command) { return ""; // no support for command descriptions in bungee } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index bdf28a203..e0ad866c8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -34,7 +34,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserBootstrap; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; @@ -48,7 +48,7 @@ import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; -import org.geysermc.geyser.platform.spigot.command.SpigotCommandSender; +import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigot1_11CraftingListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; @@ -161,6 +161,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); + this.geyserCommandManager.init(); boolean isViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; if (isViaVersion) { @@ -182,7 +183,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { boolean isPre1_12 = !isCompatible(Bukkit.getServer().getVersion(), "1.12.0"); // Set if we need to use a different method for getting a player's locale - SpigotCommandSender.setUseLegacyLocaleMethod(isPre1_12); + SpigotCommandSource.setUseLegacyLocaleMethod(isPre1_12); // We want to do this late in the server startup process to allow plugins such as ViaVersion and ProtocolLib // To do their job injecting, then connect into *that* @@ -267,7 +268,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } @Override - public CommandManager getGeyserCommandManager() { + public GeyserCommandManager getGeyserCommandManager() { return this.geyserCommandManager; } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java index b1bcfcaf8..35cb2d03a 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java @@ -30,7 +30,7 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandExecutor; +import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -39,7 +39,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -public class GeyserSpigotCommandExecutor extends CommandExecutor implements TabExecutor { +public class GeyserSpigotCommandExecutor extends GeyserCommandExecutor implements TabExecutor { public GeyserSpigotCommandExecutor(GeyserImpl geyser) { super(geyser); @@ -47,20 +47,20 @@ public class GeyserSpigotCommandExecutor extends CommandExecutor implements TabE @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - SpigotCommandSender commandSender = new SpigotCommandSender(sender); + SpigotCommandSource commandSender = new SpigotCommandSource(sender); GeyserSession session = getGeyserSession(commandSender); if (args.length > 0) { GeyserCommand geyserCommand = getCommand(args[0]); if (geyserCommand != null) { - if (!sender.hasPermission(geyserCommand.getPermission())) { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale()); + if (!sender.hasPermission(geyserCommand.permission())) { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.locale()); commandSender.sendMessage(ChatColor.RED + message); return true; } if (geyserCommand.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.locale())); return true; } geyserCommand.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); @@ -76,7 +76,7 @@ public class GeyserSpigotCommandExecutor extends CommandExecutor implements TabE @Override public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { if (args.length == 1) { - return tabComplete(new SpigotCommandSender(sender)); + return tabComplete(new SpigotCommandSource(sender)); } return Collections.emptyList(); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java index 103390ab8..22cb95c32 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java @@ -29,11 +29,11 @@ import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandMap; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import java.lang.reflect.Field; -public class GeyserSpigotCommandManager extends CommandManager { +public class GeyserSpigotCommandManager extends GeyserCommandManager { private static CommandMap COMMAND_MAP; @@ -52,7 +52,7 @@ public class GeyserSpigotCommandManager extends CommandManager { } @Override - public String getDescription(String command) { + public String description(String command) { Command cmd = COMMAND_MAP.getCommand(command.replace("/", "")); return cmd != null ? cmd.getDescription() : ""; } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java similarity index 95% rename from bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java rename to bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java index a05a6ebe0..839e4d88e 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java @@ -28,13 +28,13 @@ package org.geysermc.geyser.platform.spigot.command; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.GeyserLocale; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -public class SpigotCommandSender implements CommandSender { +public class SpigotCommandSource implements GeyserCommandSource { /** * Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version. @@ -46,7 +46,7 @@ public class SpigotCommandSender implements CommandSender { private final org.bukkit.command.CommandSender handle; private final String locale; - public SpigotCommandSender(org.bukkit.command.CommandSender handle) { + public SpigotCommandSource(org.bukkit.command.CommandSender handle) { this.handle = handle; this.locale = getSpigotLocale(); // Ensure even Java players' languages are loaded @@ -69,7 +69,7 @@ public class SpigotCommandSender implements CommandSender { } @Override - public String getLocale() { + public String locale() { return locale; } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index f5d6613c7..894368e5e 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -29,7 +29,7 @@ import com.google.inject.Inject; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserBootstrap; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; @@ -120,6 +120,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { } this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), geyser); + this.geyserCommandManager.init(); Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser), "geyser"); } @@ -139,7 +140,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { } @Override - public CommandManager getGeyserCommandManager() { + public GeyserCommandManager getGeyserCommandManager() { return this.geyserCommandManager; } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java index 825d0bf78..c8338e440 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.platform.sponge.command; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandExecutor; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandExecutor; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.session.GeyserSession; @@ -45,7 +45,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -public class GeyserSpongeCommandExecutor extends CommandExecutor implements CommandCallable { +public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements CommandCallable { public GeyserSpongeCommandExecutor(GeyserImpl geyser) { super(geyser); @@ -53,14 +53,14 @@ public class GeyserSpongeCommandExecutor extends CommandExecutor implements Comm @Override public CommandResult process(CommandSource source, String arguments) { - CommandSender commandSender = new SpongeCommandSender(source); + GeyserCommandSource commandSender = new SpongeCommandSource(source); GeyserSession session = getGeyserSession(commandSender); String[] args = arguments.split(" "); if (args.length > 0) { GeyserCommand command = getCommand(args[0]); if (command != null) { - if (!source.hasPermission(command.getPermission())) { + if (!source.hasPermission(command.permission())) { // Not ideal to use log here but we dont get a session source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); return CommandResult.success(); @@ -80,7 +80,7 @@ public class GeyserSpongeCommandExecutor extends CommandExecutor implements Comm @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) { if (arguments.split(" ").length == 1) { - return tabComplete(new SpongeCommandSender(source)); + return tabComplete(new SpongeCommandSource(source)); } return Collections.emptyList(); } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java index dce39870d..8e981f72a 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java @@ -26,12 +26,12 @@ package org.geysermc.geyser.platform.sponge.command; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandMapping; import org.spongepowered.api.text.Text; -public class GeyserSpongeCommandManager extends CommandManager { +public class GeyserSpongeCommandManager extends GeyserCommandManager { private final org.spongepowered.api.command.CommandManager handle; public GeyserSpongeCommandManager(org.spongepowered.api.command.CommandManager handle, GeyserImpl geyser) { @@ -41,7 +41,7 @@ public class GeyserSpongeCommandManager extends CommandManager { } @Override - public String getDescription(String command) { + public String description(String command) { return handle.get(command).map(CommandMapping::getCallable) .map(callable -> callable.getShortDescription(Sponge.getServer().getConsole()).orElse(Text.EMPTY)) .orElse(Text.EMPTY).toPlain(); diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java similarity index 94% rename from bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java rename to bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java index f57f3e276..664727c50 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java @@ -27,13 +27,13 @@ package org.geysermc.geyser.platform.sponge.command; import lombok.AllArgsConstructor; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.source.ConsoleSource; import org.spongepowered.api.text.Text; @AllArgsConstructor -public class SpongeCommandSender implements CommandSender { +public class SpongeCommandSource implements GeyserCommandSource { private CommandSource handle; diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 43ab4b3fe..ca41d3c1d 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -41,15 +41,15 @@ import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserBootstrap; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.platform.standalone.command.GeyserStandaloneCommandManager; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.platform.standalone.command.GeyserCommandManager; import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; import java.io.File; @@ -63,7 +63,7 @@ import java.util.stream.Collectors; public class GeyserStandaloneBootstrap implements GeyserBootstrap { - private GeyserCommandManager geyserCommandManager; + private GeyserStandaloneCommandManager geyserCommandManager; private GeyserStandaloneConfiguration geyserConfig; private GeyserStandaloneLogger geyserLogger; private IGeyserPingPassthrough geyserPingPassthrough; @@ -215,7 +215,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { logger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO); geyser = GeyserImpl.start(PlatformType.STANDALONE, this); - geyserCommandManager = new GeyserCommandManager(geyser); + geyserCommandManager = new GeyserStandaloneCommandManager(geyser); + geyserCommandManager.init(); if (gui != null) { gui.setupInterface(geyserLogger, geyserCommandManager); @@ -260,7 +261,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { } @Override - public CommandManager getGeyserCommandManager() { + public GeyserCommandManager getGeyserCommandManager() { return geyserCommandManager; } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java index 3bd2a3960..f7ce6d052 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java @@ -31,11 +31,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.ChatColor; @Log4j2 -public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, CommandSender { +public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, GeyserCommandSource { @Override protected boolean isRunning() { @@ -44,7 +44,7 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey @Override protected void runCommand(String line) { - GeyserImpl.getInstance().getCommandManager().runCommand(this, line); + GeyserImpl.getInstance().commandManager().runCommand(this, line); } @Override diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java similarity index 85% rename from bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java rename to bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java index 03d780f3c..e7b4cbe37 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java @@ -26,16 +26,16 @@ package org.geysermc.geyser.platform.standalone.command; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; -public class GeyserCommandManager extends CommandManager { +public class GeyserStandaloneCommandManager extends GeyserCommandManager { - public GeyserCommandManager(GeyserImpl geyser) { + public GeyserStandaloneCommandManager(GeyserImpl geyser) { super(geyser); } @Override - public String getDescription(String command) { + public String description(String command) { return ""; // this is not sent over the protocol, so we return none } } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java index 44faabdf5..5901da470 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java @@ -26,11 +26,12 @@ package org.geysermc.geyser.platform.standalone.gui; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.platform.standalone.GeyserStandaloneLogger; -import org.geysermc.geyser.platform.standalone.command.GeyserCommandManager; +import org.geysermc.geyser.platform.standalone.command.GeyserStandaloneCommandManager; import javax.swing.*; import javax.swing.table.DefaultTableModel; @@ -255,33 +256,34 @@ public class GeyserStandaloneGUI { * @param geyserStandaloneLogger The current logger * @param geyserCommandManager The commands manager */ - public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserCommandManager geyserCommandManager) { + public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserStandaloneCommandManager geyserCommandManager) { commandsMenu.removeAll(); optionsMenu.removeAll(); - for (Map.Entry command : geyserCommandManager.getCommands().entrySet()) { + for (Map.Entry entry : geyserCommandManager.getCommands().entrySet()) { // Remove the offhand command and any alias commands to prevent duplicates in the list - if (!command.getValue().isExecutableOnConsole() || command.getValue().getAliases().contains(command.getKey())) { + if (!entry.getValue().isExecutableOnConsole() || entry.getValue().aliases().contains(entry.getKey())) { continue; } + GeyserCommand command = (GeyserCommand) entry.getValue(); // Create the button that runs the command - boolean hasSubCommands = command.getValue().hasSubCommands(); + boolean hasSubCommands = !entry.getValue().subCommands().isEmpty(); // Add an extra menu if there are more commands that can be run - JMenuItem commandButton = hasSubCommands ? new JMenu(command.getValue().getName()) : new JMenuItem(command.getValue().getName()); - commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription()); + JMenuItem commandButton = hasSubCommands ? new JMenu(entry.getValue().name()) : new JMenuItem(entry.getValue().name()); + commandButton.getAccessibleContext().setAccessibleDescription(entry.getValue().description()); if (!hasSubCommands) { - commandButton.addActionListener(e -> command.getValue().execute(null, geyserStandaloneLogger, new String[]{ })); + commandButton.addActionListener(e -> command.execute(null, geyserStandaloneLogger, new String[]{ })); } else { // Add a submenu that's the same name as the menu can't be pressed - JMenuItem otherCommandButton = new JMenuItem(command.getValue().getName()); - otherCommandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription()); - otherCommandButton.addActionListener(e -> command.getValue().execute(null, geyserStandaloneLogger, new String[]{ })); + JMenuItem otherCommandButton = new JMenuItem(entry.getValue().name()); + otherCommandButton.getAccessibleContext().setAccessibleDescription(entry.getValue().description()); + otherCommandButton.addActionListener(e -> command.execute(null, geyserStandaloneLogger, new String[]{ })); commandButton.add(otherCommandButton); // Add a menu option for all possible subcommands - for (String subCommandName : command.getValue().getSubCommands()) { + for (String subCommandName : entry.getValue().subCommands()) { JMenuItem item = new JMenuItem(subCommandName); - item.addActionListener(e -> command.getValue().execute(null, geyserStandaloneLogger, new String[]{subCommandName})); + item.addActionListener(e -> command.execute(null, geyserStandaloneLogger, new String[]{subCommandName})); commandButton.add(item); } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 6645ef595..a79fbb30b 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -38,6 +38,7 @@ import lombok.Getter; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; @@ -145,6 +146,8 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { // Will be initialized after the proxy has been bound this.geyserCommandManager = new GeyserVelocityCommandManager(geyser); + this.geyserCommandManager.init(); + this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(geyser)); if (geyserConfig.isLegacyPingPassthrough()) { this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); @@ -174,7 +177,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { } @Override - public org.geysermc.geyser.command.CommandManager getGeyserCommandManager() { + public GeyserCommandManager getGeyserCommandManager() { return this.geyserCommandManager; } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java index 30f6c2efd..d30d9ae9e 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java @@ -27,8 +27,8 @@ package org.geysermc.geyser.platform.velocity.command; import com.velocitypowered.api.command.SimpleCommand; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandExecutor; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandExecutor; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.session.GeyserSession; @@ -38,7 +38,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -public class GeyserVelocityCommandExecutor extends CommandExecutor implements SimpleCommand { +public class GeyserVelocityCommandExecutor extends GeyserCommandExecutor implements SimpleCommand { public GeyserVelocityCommandExecutor(GeyserImpl geyser) { super(geyser); @@ -46,18 +46,18 @@ public class GeyserVelocityCommandExecutor extends CommandExecutor implements Si @Override public void execute(Invocation invocation) { - CommandSender sender = new VelocityCommandSender(invocation.source()); + GeyserCommandSource sender = new VelocityCommandSource(invocation.source()); GeyserSession session = getGeyserSession(sender); if (invocation.arguments().length > 0) { GeyserCommand command = getCommand(invocation.arguments()[0]); if (command != null) { - if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).getPermission())) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale())); + if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).permission())) { + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); return; } if (command.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale())); return; } command.execute(session, sender, invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]); @@ -71,7 +71,7 @@ public class GeyserVelocityCommandExecutor extends CommandExecutor implements Si public List suggest(Invocation invocation) { // Velocity seems to do the splitting a bit differently. This results in the same behaviour in bungeecord/spigot. if (invocation.arguments().length == 0 || invocation.arguments().length == 1) { - return tabComplete(new VelocityCommandSender(invocation.source())); + return tabComplete(new VelocityCommandSource(invocation.source())); } return Collections.emptyList(); } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java index b42c8f76e..6f9faba8f 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java @@ -26,16 +26,16 @@ package org.geysermc.geyser.platform.velocity.command; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; -public class GeyserVelocityCommandManager extends CommandManager { +public class GeyserVelocityCommandManager extends GeyserCommandManager { public GeyserVelocityCommandManager(GeyserImpl geyser) { super(geyser); } @Override - public String getDescription(String command) { + public String description(String command) { return ""; // no support for command descriptions in velocity } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java similarity index 90% rename from bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java rename to bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java index d5e4804ee..fa70d1cf7 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java @@ -29,19 +29,19 @@ import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.api.proxy.Player; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.GeyserLocale; import java.util.Locale; -public class VelocityCommandSender implements CommandSender { +public class VelocityCommandSource implements GeyserCommandSource { private final CommandSource handle; - public VelocityCommandSender(CommandSource handle) { + public VelocityCommandSource(CommandSource handle) { this.handle = handle; // Ensure even Java players' languages are loaded - GeyserLocale.loadGeyserLocale(getLocale()); + GeyserLocale.loadGeyserLocale(this.locale()); } @Override @@ -65,7 +65,7 @@ public class VelocityCommandSender implements CommandSender { } @Override - public String getLocale() { + public String locale() { if (handle instanceof Player) { Locale locale = ((Player) handle).getPlayerSettings().getLocale(); return GeyserLocale.formatLocale(locale.getLanguage() + "_" + locale.getCountry()); diff --git a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 932761d4b..e24146cb2 100644 --- a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -136,7 +136,7 @@ public class GeyserSession { } public String getLocale() { - return this.handle.getLocale(); + return this.handle.locale(); } public void sendUpstreamPacket(BedrockPacket packet) { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java index 54ca36787..bc6a07ae3 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java @@ -25,7 +25,7 @@ package org.geysermc.geyser; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.level.GeyserWorldManager; @@ -72,7 +72,7 @@ public interface GeyserBootstrap { * * @return The current CommandManager */ - CommandManager getGeyserCommandManager(); + GeyserCommandManager getGeyserCommandManager(); /** * Returns the current PingPassthrough manager diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 573934b91..b685741e7 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -52,7 +52,7 @@ import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.event.GeyserEventBus; @@ -470,12 +470,11 @@ public class GeyserImpl implements GeyserApi { skinUploader.close(); } newsHandler.shutdown(); - this.getCommandManager().getCommands().clear(); + this.commandManager().getCommands().clear(); ResourcePack.PACKS.clear(); this.eventBus.fire(new GeyserShutdownEvent()); - this.extensionManager.disableExtensions(); bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); @@ -504,6 +503,11 @@ public class GeyserImpl implements GeyserApi { return this.extensionManager; } + @Override + public GeyserCommandManager commandManager() { + return this.bootstrap.getGeyserCommandManager(); + } + @Override public EventBus eventBus() { return this.eventBus; @@ -531,10 +535,6 @@ public class GeyserImpl implements GeyserApi { return bootstrap.getGeyserConfig(); } - public CommandManager getCommandManager() { - return bootstrap.getGeyserCommandManager(); - } - public WorldManager getWorldManager() { return bootstrap.getWorldManager(); } diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java b/core/src/main/java/org/geysermc/geyser/command/CommandManager.java deleted file mode 100644 index 60af8c4e5..000000000 --- a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * 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. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.command; - -import lombok.Getter; - -import org.geysermc.common.PlatformType; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.defaults.*; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; - -import java.util.*; - -public abstract class CommandManager { - - @Getter - private final Map commands = new HashMap<>(); - - private final GeyserImpl geyser; - - public CommandManager(GeyserImpl geyser) { - this.geyser = geyser; - - registerCommand(new HelpCommand(geyser, "help", "geyser.commands.help.desc", "geyser.command.help")); - registerCommand(new ListCommand(geyser, "list", "geyser.commands.list.desc", "geyser.command.list")); - registerCommand(new ReloadCommand(geyser, "reload", "geyser.commands.reload.desc", "geyser.command.reload")); - registerCommand(new OffhandCommand(geyser, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); - registerCommand(new DumpCommand(geyser, "dump", "geyser.commands.dump.desc", "geyser.command.dump")); - registerCommand(new VersionCommand(geyser, "version", "geyser.commands.version.desc", "geyser.command.version")); - registerCommand(new SettingsCommand(geyser, "settings", "geyser.commands.settings.desc", "geyser.command.settings")); - registerCommand(new StatisticsCommand(geyser, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); - registerCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); - registerCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); - if (GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE) { - registerCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); - } - } - - public void registerCommand(GeyserCommand command) { - commands.put(command.getName(), command); - geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.commands.registered", command.getName())); - - if (command.getAliases().isEmpty()) - return; - - for (String alias : command.getAliases()) - commands.put(alias, command); - } - - public void runCommand(CommandSender sender, String command) { - if (!command.startsWith("geyser ")) - return; - - command = command.trim().replace("geyser ", ""); - String label; - String[] args; - - if (!command.contains(" ")) { - label = command.toLowerCase(); - args = new String[0]; - } else { - label = command.substring(0, command.indexOf(" ")).toLowerCase(); - String argLine = command.substring(command.indexOf(" ") + 1); - args = argLine.contains(" ") ? argLine.split(" ") : new String[] { argLine }; - } - - GeyserCommand cmd = commands.get(label); - if (cmd == null) { - geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.invalid")); - return; - } - - if (sender instanceof GeyserSession) { - cmd.execute((GeyserSession) sender, sender, args); - } else { - if (!cmd.isBedrockOnly()) { - cmd.execute(null, sender, args); - } else { - geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")); - } - } - } - - /** - * @return a list of all subcommands under {@code /geyser}. - */ - public List getCommandNames() { - return Arrays.asList(geyser.getCommandManager().getCommands().keySet().toArray(new String[0])); - } - - /** - * Returns the description of the given command - * - * @param command Command to get the description for - * @return Command description - */ - public abstract String getDescription(String command); -} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java index 20451b5e8..2b3a855aa 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java @@ -27,7 +27,9 @@ package org.geysermc.geyser.command; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; +import lombok.experimental.Accessors; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.session.GeyserSession; import javax.annotation.Nullable; @@ -35,9 +37,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +@Accessors(fluent = true) @Getter @RequiredArgsConstructor -public abstract class GeyserCommand { +public abstract class GeyserCommand implements Command { protected final String name; /** @@ -46,16 +49,16 @@ public abstract class GeyserCommand { protected final String description; protected final String permission; - @Setter private List aliases = new ArrayList<>(); - public abstract void execute(@Nullable GeyserSession session, CommandSender sender, String[] args); + public abstract void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args); /** * If false, hides the command from being shown on the Geyser Standalone GUI. * * @return true if the command can be run on the server console */ + @Override public boolean isExecutableOnConsole() { return true; } @@ -65,25 +68,22 @@ public abstract class GeyserCommand { * * @return a list of all possible subcommands, or empty if none. */ - public List getSubCommands() { + @NonNull + @Override + public List subCommands() { return Collections.emptyList(); } /** - * Shortcut to {@link #getSubCommands()}{@code .isEmpty()}. + * Shortcut to {@link #subCommands()} ()}{@code .isEmpty()}. * * @return true if there are subcommand present for this command. */ public boolean hasSubCommands() { - return !getSubCommands().isEmpty(); + return !this.subCommands().isEmpty(); } - /** - * Used to send a deny message to Java players if this command can only be used by Bedrock players. - * - * @return true if this command can only be used by Bedrock players. - */ - public boolean isBedrockOnly() { - return false; + public void setAliases(List aliases) { + this.aliases = aliases; } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java similarity index 85% rename from core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java rename to core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java index 5fa5f688b..3d08600d1 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.command; import lombok.AllArgsConstructor; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.session.GeyserSession; import javax.annotation.Nullable; @@ -39,16 +40,16 @@ import java.util.Map; * Represents helper functions for listening to {@code /geyser} commands. */ @AllArgsConstructor -public class CommandExecutor { +public class GeyserCommandExecutor { protected final GeyserImpl geyser; public GeyserCommand getCommand(String label) { - return geyser.getCommandManager().getCommands().get(label); + return (GeyserCommand) geyser.commandManager().commands().get(label); } @Nullable - public GeyserSession getGeyserSession(CommandSender sender) { + public GeyserSession getGeyserSession(GeyserCommandSource sender) { if (sender.isConsole()) { return null; } @@ -70,20 +71,19 @@ public class CommandExecutor { * If the command sender does not have the permission for a given command, the command will not be shown. * @return A list of command names to include in the tab complete */ - public List tabComplete(CommandSender sender) { + public List tabComplete(GeyserCommandSource sender) { if (getGeyserSession(sender) != null) { // Bedrock doesn't get tab completions or argument suggestions return Collections.emptyList(); } List availableCommands = new ArrayList<>(); - Map commands = geyser.getCommandManager().getCommands(); + Map commands = geyser.commandManager().getCommands(); // Only show commands they have permission to use - for (Map.Entry entry : commands.entrySet()) { - GeyserCommand geyserCommand = entry.getValue(); - if (sender.hasPermission(geyserCommand.getPermission())) { - + for (Map.Entry entry : commands.entrySet()) { + Command geyserCommand = entry.getValue(); + if (sender.hasPermission(geyserCommand.permission())) { if (geyserCommand.isBedrockOnly()) { // Don't show commands the JE player can't run continue; diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java new file mode 100644 index 000000000..9cce0e9ce --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.command; + +import lombok.Getter; + +import lombok.RequiredArgsConstructor; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.common.PlatformType; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.command.CommandExecutor; +import org.geysermc.geyser.api.command.CommandManager; +import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; +import org.geysermc.geyser.command.defaults.*; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +@RequiredArgsConstructor +public abstract class GeyserCommandManager extends CommandManager { + + @Getter + private final Map commands = new HashMap<>(); + + private final GeyserImpl geyser; + + public void init() { + register(new HelpCommand(geyser, "help", "geyser.commands.help.desc", "geyser.command.help")); + register(new ListCommand(geyser, "list", "geyser.commands.list.desc", "geyser.command.list")); + register(new ReloadCommand(geyser, "reload", "geyser.commands.reload.desc", "geyser.command.reload")); + register(new OffhandCommand(geyser, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); + register(new DumpCommand(geyser, "dump", "geyser.commands.dump.desc", "geyser.command.dump")); + register(new VersionCommand(geyser, "version", "geyser.commands.version.desc", "geyser.command.version")); + register(new SettingsCommand(geyser, "settings", "geyser.commands.settings.desc", "geyser.command.settings")); + register(new StatisticsCommand(geyser, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); + register(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); + register(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); + if (GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE) { + register(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); + } + + this.geyser.eventBus().fire(new GeyserDefineCommandsEvent(this, this.commands)); + } + + @Override + public void register(@NonNull Command command) { + this.commands.put(command.name(), command); + this.geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.commands.registered", command.name())); + + if (command.aliases().isEmpty()) { + return; + } + + for (String alias : command.aliases()) { + this.commands.put(alias, command); + } + } + + @Override + public void unregister(@NonNull Command command) { + this.commands.remove(command.name(), command); + + if (command.aliases().isEmpty()) { + return; + } + + for (String alias : command.aliases()) { + this.commands.remove(alias, command); + } + } + + @NotNull + @Override + public Map commands() { + return Collections.unmodifiableMap(this.commands); + } + + public void runCommand(GeyserCommandSource sender, String command) { + if (!command.startsWith("geyser ")) + return; + + command = command.trim().replace("geyser ", ""); + String label; + String[] args; + + if (!command.contains(" ")) { + label = command.toLowerCase(); + args = new String[0]; + } else { + label = command.substring(0, command.indexOf(" ")).toLowerCase(); + String argLine = command.substring(command.indexOf(" ") + 1); + args = argLine.contains(" ") ? argLine.split(" ") : new String[] { argLine }; + } + + Command cmd = commands.get(label); + if (cmd == null) { + geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.invalid")); + return; + } + + if (cmd instanceof GeyserCommand) { + if (sender instanceof GeyserSession) { + ((GeyserCommand) cmd).execute((GeyserSession) sender, sender, args); + } else { + if (!cmd.isBedrockOnly()) { + ((GeyserCommand) cmd).execute(null, sender, args); + } else { + geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")); + } + } + } + } + + /** + * Returns the description of the given command + * + * @param command Command to get the description for + * @return Command description + */ + public abstract String description(String command); + + @Override + protected Command.Builder provideBuilder(Class sourceType) { + return new CommandBuilder<>(sourceType); + } + + @RequiredArgsConstructor + public static class CommandBuilder implements Command.Builder { + private final Class sourceType; + private String name; + private String description = ""; + private String permission = ""; + private List aliases; + private boolean executableOnConsole = true; + private List subCommands; + private boolean bedrockOnly; + private CommandExecutor executor; + + public CommandBuilder name(String name) { + this.name = name; + return this; + } + + public CommandBuilder description(String description) { + this.description = description; + return this; + } + + public CommandBuilder permission(String permission) { + this.permission = permission; + return this; + } + + public CommandBuilder aliases(List aliases) { + this.aliases = aliases; + return this; + } + + public CommandBuilder executableOnConsole(boolean executableOnConsole) { + this.executableOnConsole = executableOnConsole; + return this; + } + + public CommandBuilder subCommands(List subCommands) { + this.subCommands = subCommands; + return this; + } + + public CommandBuilder bedrockOnly(boolean bedrockOnly) { + this.bedrockOnly = bedrockOnly; + return this; + } + + public CommandBuilder executor(CommandExecutor executor) { + this.executor = executor; + return this; + } + + public GeyserCommand build() { + if (this.name == null || this.name.isBlank()) { + throw new IllegalArgumentException("Command cannot be null or blank!"); + } + + return new GeyserCommand(this.name, this.description, this.permission) { + + @SuppressWarnings("unchecked") + @Override + public void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args) { + Class sourceType = CommandBuilder.this.sourceType; + CommandExecutor executor = CommandBuilder.this.executor; + if (sourceType.isInstance(session)) { + executor.execute((T) session, this, args); + return; + } + + if (sourceType.isInstance(sender)) { + executor.execute((T) sender, this, args); + return; + } + + GeyserImpl.getInstance().getLogger().debug("Ignoring command " + this.name + " due to no suitable sender."); + } + + @NonNull + @Override + public List aliases() { + return CommandBuilder.this.aliases == null ? Collections.emptyList() : CommandBuilder.this.aliases; + } + + @NonNull + @Override + public List subCommands() { + return CommandBuilder.this.subCommands == null ? Collections.emptyList() : CommandBuilder.this.subCommands; + } + + @Override + public boolean isBedrockOnly() { + return CommandBuilder.this.bedrockOnly; + } + + @Override + public boolean isExecutableOnConsole() { + return CommandBuilder.this.executableOnConsole; + } + }; + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java new file mode 100644 index 000000000..eabccc243 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.command; + +import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.text.GeyserLocale; + +/** + * Implemented on top of any class that can send a command. + * For example, it wraps around Spigot's CommandSender class. + */ +public interface GeyserCommandSource extends CommandSource { + + /** + * {@inheritDoc} + */ + default String locale() { + return GeyserLocale.getDefaultLocale(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java index 18546c914..350b98f04 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; @@ -36,11 +36,11 @@ public class AdvancedTooltipsCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (session != null) { String onOrOff = session.isAdvancedTooltips() ? "off" : "on"; session.setAdvancedTooltips(!session.isAdvancedTooltips()); - session.sendMessage("§l§e" + MinecraftLocale.getLocaleString("debug.prefix", session.getLocale()) + " §r" + MinecraftLocale.getLocaleString("debug.advanced_tooltips." + onOrOff, session.getLocale())); + session.sendMessage("§l§e" + MinecraftLocale.getLocaleString("debug.prefix", session.locale()) + " §r" + MinecraftLocale.getLocaleString("debug.advanced_tooltips." + onOrOff, session.locale())); session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory()); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java index 169158572..2aea5f4df 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; @@ -35,7 +35,7 @@ public class AdvancementsCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (session != null) { session.getAdvancementsCache().buildAndShowMenuForm(); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java index bd98d2b31..32382526a 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java @@ -29,9 +29,10 @@ import com.fasterxml.jackson.core.util.DefaultIndenter; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.AsteriskSerializer; @@ -58,10 +59,10 @@ public class DumpCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { // Only allow the console to create dumps on Geyser Standalone if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); return; } @@ -80,7 +81,7 @@ public class DumpCommand extends GeyserCommand { AsteriskSerializer.showSensitive = showSensitive; - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", sender.locale())); String dumpData; try { if (offlineDump) { @@ -92,7 +93,7 @@ public class DumpCommand extends GeyserCommand { dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog)); } } catch (IOException e) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.locale())); geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e); return; } @@ -100,21 +101,21 @@ public class DumpCommand extends GeyserCommand { String uploadedDumpUrl = ""; if (offlineDump) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.writing", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.writing", sender.locale())); try { FileOutputStream outputStream = new FileOutputStream(GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile()); outputStream.write(dumpData.getBytes()); outputStream.close(); } catch (IOException e) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.write_error", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.write_error", sender.locale())); geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.write_error_short"), e); return; } uploadedDumpUrl = "dump.json"; } else { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.uploading", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.uploading", sender.locale())); String response; JsonNode responseNode; @@ -122,27 +123,28 @@ public class DumpCommand extends GeyserCommand { response = WebUtils.post(DUMP_URL + "documents", dumpData); responseNode = MAPPER.readTree(response); } catch (IOException e) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.locale())); geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e); return; } if (!responseNode.has("key")) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.getLocale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response)); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.locale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response)); return; } uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText(); } - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.message", sender.getLocale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.message", sender.locale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl); if (!sender.isConsole()) { geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.commands.dump.created", sender.name(), uploadedDumpUrl)); } } + @NonNull @Override - public List getSubCommands() { + public List subCommands() { return Arrays.asList("offline", "full", "logs"); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java index 85682b294..fccb1b267 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java @@ -27,7 +27,8 @@ package org.geysermc.geyser.command.defaults; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.session.GeyserSession; @@ -54,25 +55,25 @@ public class HelpCommand extends GeyserCommand { * @param args Not used. */ @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { int page = 1; int maxPage = 1; - String header = GeyserLocale.getPlayerLocaleString("geyser.commands.help.header", sender.getLocale(), page, maxPage); + String header = GeyserLocale.getPlayerLocaleString("geyser.commands.help.header", sender.locale(), page, maxPage); sender.sendMessage(header); - Map cmds = geyser.getCommandManager().getCommands(); - for (Map.Entry entry : cmds.entrySet()) { - GeyserCommand cmd = entry.getValue(); + Map cmds = geyser.commandManager().getCommands(); + for (Map.Entry entry : cmds.entrySet()) { + Command cmd = entry.getValue(); // Standalone hack-in since it doesn't have a concept of permissions - if (geyser.getPlatformType() == PlatformType.STANDALONE || sender.hasPermission(cmd.getPermission())) { + if (geyser.getPlatformType() == PlatformType.STANDALONE || sender.hasPermission(cmd.permission())) { // Only list commands the player can actually run if (cmd.isBedrockOnly() && session == null) { continue; } sender.sendMessage(ChatColor.YELLOW + "/geyser " + entry.getKey() + ChatColor.WHITE + ": " + - GeyserLocale.getPlayerLocaleString(cmd.getDescription(), sender.getLocale())); + GeyserLocale.getPlayerLocaleString(cmd.description(), sender.locale())); } } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java index f1004c3fb..8382d7a29 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.command.defaults; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -44,8 +44,8 @@ public class ListCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { - String message = GeyserLocale.getPlayerLocaleString("geyser.commands.list.message", sender.getLocale(), + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { + String message = GeyserLocale.getPlayerLocaleString("geyser.commands.list.message", sender.locale(), geyser.getSessionManager().size(), geyser.getSessionManager().getAllSessions().stream().map(GeyserSession::name).collect(Collectors.joining(" "))); diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java index 1d29d5122..a9f265f6e 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java @@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockUtils; @@ -41,7 +41,7 @@ public class OffhandCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (session == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java index b6a728382..31e17faad 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.command.defaults; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -42,12 +42,12 @@ public class ReloadCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { return; } - String message = GeyserLocale.getPlayerLocaleString("geyser.commands.reload.message", sender.getLocale()); + String message = GeyserLocale.getPlayerLocaleString("geyser.commands.reload.message", sender.locale()); sender.sendMessage(message); diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java index 58d778ba9..a8e8a374e 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.command.defaults; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.SettingsUtils; @@ -37,7 +37,7 @@ public class SettingsCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (session != null) { session.sendForm(SettingsUtils.buildForm(session)); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java index e54b0fb9b..c898f32a9 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.command.defaults; import com.github.steveice10.mc.protocol.data.game.ClientCommand; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; @@ -39,7 +39,7 @@ public class StatisticsCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (session == null) return; session.setWaitingForStatistics(true); diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java index 903e3bf4b..b038fa0ff 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.command.defaults; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -46,9 +46,9 @@ public class StopCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); return; } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java index 6ec816b12..89bea3343 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.command.defaults; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.session.GeyserSession; @@ -54,7 +54,7 @@ public class VersionCommand extends GeyserCommand { } @Override - public void execute(GeyserSession session, CommandSender sender, String[] args) { + public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { String bedrockVersions; List supportedCodecs = MinecraftProtocol.SUPPORTED_BEDROCK_CODECS; if (supportedCodecs.size() > 1) { @@ -70,12 +70,12 @@ public class VersionCommand extends GeyserCommand { javaVersions = supportedJavaVersions.get(0); } - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.version", sender.getLocale(), + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.version", sender.locale(), GeyserImpl.NAME, GeyserImpl.VERSION, javaVersions, bedrockVersions)); // Disable update checking in dev mode and for players in Geyser Standalone if (GeyserImpl.getInstance().productionEnvironment() && !(!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.locale())); try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("git.properties")) { Properties gitProp = new Properties(); gitProp.load(stream); @@ -86,17 +86,17 @@ public class VersionCommand extends GeyserCommand { int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number")); if (latestBuildNum == buildNum) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale())); } else { sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.outdated", - sender.getLocale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/")); + sender.locale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/")); } } else { throw new AssertionError("buildNumber missing"); } } catch (IOException | AssertionError | NumberFormatException e) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.version.failed"), e); - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.locale())); } } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index adeccdd01..77a1a199c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -356,7 +356,7 @@ public class Entity { public void setDisplayName(EntityMetadata, ?> entityMetadata) { Optional name = entityMetadata.getValue(); if (name.isPresent()) { - nametag = MessageTranslator.convertMessage(name.get(), session.getLocale()); + nametag = MessageTranslator.convertMessage(name.get(), session.locale()); dirtyMetadata.put(EntityData.NAMETAG, nametag); } else if (!nametag.isEmpty()) { // Clear nametag diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java index 93a042826..eaf71e087 100644 --- a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.event; +import net.kyori.event.EventSubscriber; import net.kyori.event.SimpleEventBus; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.event.Event; @@ -37,17 +38,12 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; public class GeyserEventBus implements EventBus { private final SimpleEventBus bus = new SimpleEventBus<>(Event.class); - @NonNull - @Override - public EventSubscription subscribe(@NonNull Class eventClass, @NonNull Consumer consumer) { - return this.subscribe(eventClass, consumer, null, Subscribe.Priority.NORMAL); - } - @NonNull @Override public EventSubscription subscribe(@NonNull Extension extension, @NonNull Class eventClass, @NonNull Consumer consumer) { @@ -86,6 +82,11 @@ public class GeyserEventBus implements EventBus { } } + @Override + public void unregisterAll(@NonNull Extension extension) { + this.bus.unregister((Predicate>) subscriber -> extension.equals(((GeyserEventSubscription) subscriber).owner())); + } + @Override public boolean fire(@NonNull Event event) { return this.bus.post(event).wasSuccessful(); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionContainer.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionContainer.java index 5b2e01842..a26415a13 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionContainer.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionContainer.java @@ -29,6 +29,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.experimental.Accessors; +import org.geysermc.geyser.api.event.ExtensionEventBus; import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.ExtensionLoader; @@ -45,6 +46,7 @@ public class GeyserExtensionContainer { private final ExtensionDescription description; private final ExtensionLoader loader; private final ExtensionLogger logger; + private final ExtensionEventBus eventBus; @Getter(AccessLevel.NONE) protected boolean enabled; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index a539dcb15..972b106d6 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.extension; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.ExtensionEventBus; import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.ExtensionLoader; @@ -35,6 +36,7 @@ import org.geysermc.geyser.api.extension.ExtensionLogger; import org.geysermc.geyser.api.extension.ExtensionManager; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; +import org.geysermc.geyser.extension.event.GeyserExtensionEventBus; import org.geysermc.geyser.text.GeyserLocale; import java.io.IOException; @@ -83,12 +85,12 @@ public class GeyserExtensionLoader extends ExtensionLoader { } this.classLoaders.put(description.name(), loader); - return this.setup(loader.extension(), description, dataFolder); + return this.setup(loader.extension(), description, dataFolder, new GeyserExtensionEventBus(GeyserImpl.getInstance().eventBus(), loader.extension())); } - private GeyserExtensionContainer setup(Extension extension, GeyserExtensionDescription description, Path dataFolder) { + private GeyserExtensionContainer setup(Extension extension, GeyserExtensionDescription description, Path dataFolder, ExtensionEventBus eventBus) { GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.name()); - GeyserExtensionContainer container = new GeyserExtensionContainer(extension, dataFolder, description, this, logger); + GeyserExtensionContainer container = new GeyserExtensionContainer(extension, dataFolder, description, this, logger, eventBus); extension.onLoad(); return container; } @@ -246,6 +248,12 @@ public class GeyserExtensionLoader extends ExtensionLoader { return this.extensionContainers.get(extension).description(); } + @NonNull + @Override + protected ExtensionEventBus eventBus(@NonNull Extension extension) { + return this.extensionContainers.get(extension).eventBus(); + } + @NonNull @Override protected ExtensionLogger logger(@NonNull Extension extension) { diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index a72712f16..936cde471 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -90,15 +90,18 @@ public class GeyserExtensionManager extends ExtensionManager { public void enableExtension(Extension extension) { if (!extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.description().name())); extension.setEnabled(true); + GeyserImpl.getInstance().eventBus().register(extension, extension); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.description().name())); } } private void disableExtension(@NonNull Extension extension) { if (extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.description().name())); + GeyserImpl.getInstance().eventBus().unregisterAll(extension); + extension.setEnabled(false); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.description().name())); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java new file mode 100644 index 000000000..4104871fa --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension.event; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.event.Event; +import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventSubscription; +import org.geysermc.geyser.api.event.ExtensionEventBus; +import org.geysermc.geyser.api.extension.Extension; + +import java.util.Set; +import java.util.function.Consumer; + +public record GeyserExtensionEventBus(EventBus eventBus, + Extension extension) implements ExtensionEventBus { + @NonNull + @Override + public EventSubscription subscribe(@NonNull Class eventClass, @NonNull Consumer consumer) { + return this.eventBus.subscribe(this.extension, eventClass, consumer); + } + + @Override + public void register(@NonNull Object eventHolder) { + this.eventBus.register(this.extension, eventHolder); + } + + @Override + public void unregisterAll() { + this.eventBus.unregisterAll(this.extension); + } + + @NonNull + @Override + public EventSubscription subscribe(@NonNull Extension extension, @NonNull Class eventClass, @NonNull Consumer consumer) { + return this.eventBus.subscribe(extension, eventClass, consumer); + } + + @Override + public void unsubscribe(@NonNull EventSubscription subscription) { + this.eventBus.unsubscribe(subscription); + } + + @Override + public void register(@NonNull Extension extension, @NonNull Object eventHolder) { + this.eventBus.register(extension, eventHolder); + } + + @Override + public void unregisterAll(@NonNull Extension extension) { + this.eventBus.unregisterAll(extension); + } + + @Override + public boolean fire(@NonNull Event event) { + return this.eventBus.fire(event); + } + + @NonNull + @Override + public Set> subscriptions(@NonNull Class eventClass) { + return this.eventBus.subscriptions(eventClass); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java index d6f72b8d0..d203b0311 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java @@ -115,7 +115,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Changing the item in the input slot resets the name field on Bedrock, but // does not result in a FilterTextPacket - String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getNbt()), session.getLocale()); + String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getNbt()), session.locale()); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); session.sendDownstreamPacket(renameItemPacket); @@ -427,7 +427,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { String originalName = ItemUtils.getCustomName(anvilContainer.getInput().getNbt()); if (bedrock && originalName != null && anvilContainer.getNewName() != null) { // Check text and formatting - String legacyOriginalName = MessageTranslator.convertMessageLenient(originalName, session.getLocale()); + String legacyOriginalName = MessageTranslator.convertMessageLenient(originalName, session.locale()); return !legacyOriginalName.equals(anvilContainer.getNewName()); } return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getNbt())); diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index f547c4dce..5686e3d98 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -112,7 +112,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks()); session.sendUpstreamPacket(resourcePacksInfo); - GeyserLocale.loadGeyserLocale(session.getLocale()); + GeyserLocale.loadGeyserLocale(session.locale()); return true; } @@ -208,7 +208,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { if (session.isLoggingIn()) { SetTitlePacket titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - titlePacket.setText(GeyserLocale.getPlayerLocaleString("geyser.auth.login.wait", session.getLocale())); + titlePacket.setText(GeyserLocale.getPlayerLocaleString("geyser.auth.login.wait", session.locale())); titlePacket.setFadeInTime(0); titlePacket.setFadeOutTime(1); titlePacket.setStayTime(2); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 7ea65e49e..591934d6d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -79,7 +79,7 @@ import org.geysermc.floodgate.util.BedrockData; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.connection.GeyserConnection; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; import org.geysermc.geyser.entity.InteractiveTagManager; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; @@ -122,7 +122,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @Getter -public class GeyserSession implements GeyserConnection, CommandSender { +public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final GeyserImpl geyser; private final UpstreamSession upstream; @@ -876,7 +876,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { if (cause instanceof UnexpectedEncryptionException) { if (remoteAuthType != AuthType.FLOODGATE) { // Server expects online mode - disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.authentication_type_mismatch", getLocale()); + disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.authentication_type_mismatch", locale()); // Explain that they may be looking for Floodgate. geyser.getLogger().warning(GeyserLocale.getLocaleStringLog( geyser.getPlatformType() == PlatformType.STANDALONE ? @@ -886,14 +886,14 @@ public class GeyserSession implements GeyserConnection, CommandSender { )); } else { // Likely that Floodgate is not configured correctly. - disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.floodgate_login_error", getLocale()); + disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.floodgate_login_error", locale()); if (geyser.getPlatformType() == PlatformType.STANDALONE) { geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.remote.floodgate_login_error_standalone")); } } } else if (cause instanceof ConnectException) { // Server is offline, probably - disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.server_offline", getLocale()); + disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.server_offline", locale()); } else { disconnectMessage = MessageTranslator.convertMessageLenient(event.getReason()); } @@ -1156,7 +1156,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { } @Override - public String getLocale() { + public String locale() { return clientData.getLanguageCode(); } diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 8cfc73d7e..fc6c37356 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -80,7 +80,7 @@ public final class SessionManager { public void disconnectAll(String message) { Collection sessions = getAllSessions(); for (GeyserSession session : sessions) { - session.disconnect(GeyserLocale.getPlayerLocaleString(message, session.getLocale())); + session.disconnect(GeyserLocale.getPlayerLocaleString(message, session.locale())); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index 9d3e4f5aa..5d5779ae7 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -72,14 +72,14 @@ public class AdvancementsCache { public void buildAndShowMenuForm() { SimpleForm.Builder builder = SimpleForm.builder() - .translator(MinecraftLocale::getLocaleString, session.getLocale()) + .translator(MinecraftLocale::getLocaleString, session.locale()) .title("gui.advancements"); boolean hasAdvancements = false; for (Map.Entry advancement : storedAdvancements.entrySet()) { if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement hasAdvancements = true; - builder.button(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), session.getLocale())); + builder.button(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), session.locale())); } } @@ -128,7 +128,7 @@ public class AdvancementsCache { */ public void buildAndShowListForm() { GeyserAdvancement categoryAdvancement = storedAdvancements.get(currentAdvancementCategoryId); - String language = session.getLocale(); + String language = session.locale(); SimpleForm.Builder builder = SimpleForm.builder() @@ -190,7 +190,7 @@ public class AdvancementsCache { */ public void buildAndShowInfoForm(GeyserAdvancement advancement) { // Cache language for easier access - String language = session.getLocale(); + String language = session.locale(); String earned = isEarned(advancement) ? "yes" : "no"; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java b/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java index 7cfeaa165..cd1bc4c98 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java @@ -57,7 +57,7 @@ public class BossBar { BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); bossEventPacket.setAction(BossEventPacket.Action.CREATE); - bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.getLocale())); + bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.locale())); bossEventPacket.setHealthPercentage(health); bossEventPacket.setColor(color); bossEventPacket.setOverlay(overlay); @@ -71,7 +71,7 @@ public class BossBar { BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); bossEventPacket.setAction(BossEventPacket.Action.UPDATE_NAME); - bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.getLocale())); + bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.locale())); session.sendUpstreamPacket(bossEventPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java index 6a2182279..34e9364ce 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java @@ -157,7 +157,7 @@ public abstract class ItemTranslator { nbt = translateDisplayProperties(session, nbt, bedrockItem); if (session.isAdvancedTooltips()) { - nbt = addAdvancedTooltips(nbt, session.getItemMappings().getMapping(stack), session.getLocale()); + nbt = addAdvancedTooltips(nbt, session.getItemMappings().getMapping(stack), session.locale()); } ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), nbt); @@ -474,7 +474,7 @@ public abstract class ItemTranslator { String name = ((StringTag) display.get("Name")).getValue(); // Get the translated name and prefix it with a reset char - name = MessageTranslator.convertMessageLenient(name, session.getLocale()); + name = MessageTranslator.convertMessageLenient(name, session.locale()); // Add the new name tag display.put(new StringTag("Name", name)); @@ -500,7 +500,7 @@ public abstract class ItemTranslator { String translationKey = mapping.getTranslationString(); // Reset formatting since Bedrock defaults to italics - display.put(new StringTag("Name", "§r§" + translationColor + MinecraftLocale.getLocaleString(translationKey, session.getLocale()))); + display.put(new StringTag("Name", "§r§" + translationColor + MinecraftLocale.getLocaleString(translationKey, session.locale()))); } return tag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java index c3abf2495..4a91110dc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java @@ -42,7 +42,7 @@ public class AxolotlBucketTranslator extends NbtItemStackTranslator { // Bedrock Edition displays the properties of the axolotl. Java does not. // To work around this, set the custom name to the Axolotl translation and it's displayed correctly itemTag.put(new ByteTag("AppendCustomName", (byte) 1)); - itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.getLocale()))); + itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale()))); // Boilerplate required so the nametag does not appear as "Bucket of " itemTag.put(new StringTag("ColorID", "")); itemTag.put(new StringTag("BodyID", "")); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java index 42cfc0439..d50a8c579 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java @@ -61,7 +61,7 @@ public class BasicItemTranslator extends NbtItemStackTranslator { List lore = new ArrayList<>(); for (Tag tag : listTag.getValue()) { if (!(tag instanceof StringTag)) continue; - lore.add(new StringTag("", MessageTranslator.convertMessageLenient(((StringTag) tag).getValue(), session.getLocale()))); + lore.add(new StringTag("", MessageTranslator.convertMessageLenient(((StringTag) tag).getValue(), session.locale()))); } displayTag.put(new ListTag("Lore", lore)); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java index 680be00fd..44308aeee 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java @@ -56,7 +56,7 @@ public class PlayerHeadTranslator extends NbtItemStackTranslator { } // Add correct name of player skull // TODO: It's always yellow, even with a custom name. Handle? - String displayName = "\u00a7r\u00a7e" + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.getLocale()).replace("%s", name.getValue()); + String displayName = "\u00a7r\u00a7e" + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name.getValue()); if (!itemTag.contains("display")) { itemTag.put(new CompoundTag("display")); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java index dbacc75fe..5fd101e8b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java @@ -50,7 +50,7 @@ public class TropicalFishBucketTranslator extends NbtItemStackTranslator { public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { // Prevent name from appearing as "Bucket of" itemTag.put(new ByteTag("AppendCustomName", (byte) 1)); - itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.getLocale()))); + itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale()))); // Add Java's client side lore tag Tag bucketVariantTag = itemTag.get("BucketVariantTag"); if (bucketVariantTag instanceof IntTag) { @@ -66,10 +66,10 @@ public class TropicalFishBucketTranslator extends NbtItemStackTranslator { int predefinedVariantId = TropicalFishEntity.getPredefinedId(varNumber); if (predefinedVariantId != -1) { Component tooltip = Component.translatable("entity.minecraft.tropical_fish.predefined." + predefinedVariantId, LORE_STYLE); - lore.add(0, new StringTag("", MessageTranslator.convertMessage(tooltip, session.getLocale()))); + lore.add(0, new StringTag("", MessageTranslator.convertMessage(tooltip, session.locale()))); } else { Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(varNumber), LORE_STYLE); - lore.add(0, new StringTag("", MessageTranslator.convertMessage(typeTooltip, session.getLocale()))); + lore.add(0, new StringTag("", MessageTranslator.convertMessage(typeTooltip, session.locale()))); byte baseColor = TropicalFishEntity.getBaseColor(varNumber); byte patternColor = TropicalFishEntity.getPatternColor(varNumber); @@ -78,7 +78,7 @@ public class TropicalFishBucketTranslator extends NbtItemStackTranslator { colorTooltip = colorTooltip.append(Component.text(", ", LORE_STYLE)) .append(Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(patternColor), LORE_STYLE)); } - lore.add(1, new StringTag("", MessageTranslator.convertMessage(colorTooltip, session.getLocale()))); + lore.add(1, new StringTag("", MessageTranslator.convertMessage(colorTooltip, session.locale()))); } ListTag loreTag = displayTag.get("Lore"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java index 73ca9b222..1a955c1a8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -42,7 +42,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator }); textPacket.setNeedsTranslation(false); - textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.getLocale())); + textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.locale())); session.sendUpstreamPacket(textPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 28ebca926..18712dbf5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -43,7 +43,8 @@ import lombok.Getter; import lombok.ToString; import net.kyori.adventure.text.format.NamedTextColor; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.api.event.downstream.ServerDefineCommandsEvent; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -112,7 +113,7 @@ public class JavaCommandsTranslator extends PacketTranslator commandData = new ArrayList<>(); IntSet commandNodes = new IntOpenHashSet(); @@ -141,15 +142,20 @@ public class JavaCommandsTranslator extends PacketTranslator new HashSet<>()).add(node.getName().toLowerCase()); } + ServerDefineCommandsEvent event = new ServerDefineCommandsEvent(session, commands.keySet()); + session.getGeyser().eventBus().fire(event); + if (event.isCancelled()) { + return; + } + // The command flags, not sure what these do apart from break things List flags = Collections.emptyList(); // Loop through all the found commands - for (Map.Entry> entry : commands.entrySet()) { String commandName = entry.getValue().iterator().next(); // We know this has a value @@ -236,7 +242,7 @@ public class JavaCommandsTranslator extends PacketTranslator 256) { - session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.chat.too_long", session.getLocale(), message.length())); + session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.chat.too_long", session.locale(), message.length())); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java index 5a1063a10..8fd079702 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -226,7 +226,7 @@ public class LoginEncryptionUtils { session.sendForm( SimpleForm.builder() - .translator(GeyserLocale::getPlayerLocaleString, session.getLocale()) + .translator(GeyserLocale::getPlayerLocaleString, session.locale()) .title("geyser.auth.login.form.notice.title") .content("geyser.auth.login.form.notice.desc") .optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled) @@ -257,14 +257,14 @@ public class LoginEncryptionUtils { return; } - session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); + session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.locale())); })); } public static void buildAndShowLoginDetailsWindow(GeyserSession session) { session.sendForm( CustomForm.builder() - .translator(GeyserLocale::getPlayerLocaleString, session.getLocale()) + .translator(GeyserLocale::getPlayerLocaleString, session.locale()) .title("geyser.auth.login.form.details.title") .label("geyser.auth.login.form.details.desc") .input("geyser.auth.login.form.details.email", "account@geysermc.org", "") @@ -286,7 +286,7 @@ public class LoginEncryptionUtils { public static void buildAndShowMicrosoftAuthenticationWindow(GeyserSession session) { session.sendForm( SimpleForm.builder() - .translator(GeyserLocale::getPlayerLocaleString, session.getLocale()) + .translator(GeyserLocale::getPlayerLocaleString, session.locale()) .title("geyser.auth.login.form.notice.btn_login.microsoft") .button("geyser.auth.login.method.browser") .button("geyser.auth.login.method.password") @@ -303,7 +303,7 @@ public class LoginEncryptionUtils { } else if (response.getClickedButtonId() == 1) { buildAndShowLoginDetailsWindow(session); } else { - session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); + session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.locale())); } })); } @@ -326,7 +326,7 @@ public class LoginEncryptionUtils { } if (response.getClickedButtonId() == 1) { - session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); + session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.locale())); } }) ); diff --git a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java index ea3412451..75c26cade 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java @@ -45,7 +45,7 @@ public class SettingsUtils { */ public static CustomForm buildForm(GeyserSession session) { // Cache the language for cleaner access - String language = session.getLocale(); + String language = session.locale(); CustomForm.Builder builder = CustomForm.builder() .translator(SettingsUtils::translateEntry, language) diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 447661e21..3324ec577 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -53,7 +53,7 @@ public class StatisticsUtils { */ public static void buildAndSendStatisticsMenu(GeyserSession session) { // Cache the language for cleaner access - String language = session.getLocale(); + String language = session.locale(); session.sendForm( SimpleForm.builder()