### Runtime Command Registration Example Source: https://github.com/revxrsal/lamp/wiki/Orphan-commands This example demonstrates registering an orphan command with a path provided by command-line arguments and then polling for input. ```java public static void main(String[] args) { ConsoleCommandHandler handler = ConsoleCommandHandler.create(); handler.register(Orphans.path(args[0]).handler(new Foo())); handler.pollInput(); } where args[0] = "buzz" ``` > buzz bar Hello! ``` -------------------------------- ### Example Command Using Integer Parameter Source: https://github.com/revxrsal/lamp/wiki/Value-resolvers A sample command that utilizes the registered integer value resolver for the 'times' parameter. ```java @Command("repeat") public void repeat(CommandActor actor, int times, String value) { for (int i = 0; i < times; i++) actor.reply("#" + i + ": " + value); } ``` -------------------------------- ### Gradle Setup for Lamp Framework Source: https://context7.com/revxrsal/lamp/llms.txt Add the common Lamp dependency and the module for your target platform to your build.gradle.kts. Ensure parameter names are preserved for automatic usage generation. ```kotlin repositories { mavenCentral() } dependencies { val lampVersion = "4.0.0-rc.16" // Required for all platforms implementation("io.github.revxrsal:lamp.common:$lampVersion") // Pick ONE of the following platform modules: implementation("io.github.revxrsal:lamp.bukkit:$lampVersion") // Bukkit / Spigot / Paper implementation("io.github.revxrsal:lamp.bungee:$lampVersion") // BungeeCord implementation("io.github.revxrsal:lamp.velocity:$lampVersion") // Velocity implementation("io.github.revxrsal:lamp.sponge:$lampVersion") // Sponge implementation("io.github.revxrsal:lamp.jda:$lampVersion") // JDA (Discord) implementation("io.github.revxrsal:lamp.fabric:$lampVersion") // Fabric implementation("io.github.revxrsal:lamp.minestom:$lampVersion") // Minestom implementation("io.github.revxrsal:lamp.cli:$lampVersion") // CLI apps implementation("io.github.revxrsal:lamp.brigadier:$lampVersion") // Brigadier bridge } // Preserve parameter names for automatic usage generation tasks.withType { options.compilerArgs += "-parameters" } ``` -------------------------------- ### Define a simple "hello" command Source: https://github.com/revxrsal/lamp/wiki/Creating-a--hello-command Create a command method annotated with @Command. This example replies with "Why, hello there!" when the /hello command is executed. ```java @Command("hello") public void sayHello(BukkitCommandActor actor){ actor.reply("Why, hello there!"); } ``` -------------------------------- ### Help Command Implementation Source: https://github.com/revxrsal/lamp/wiki/Command-help Implement a command to display help messages using `CommandHelp`. This example paginates the help entries, showing 7 entries per page, and replies them to the actor. ```java @Command("something help") public void help(CommandActor actor, CommandHelp helpEntries, @Default("1") int page) { for (String entry : helpEntries.paginate(page, 7)) // 7 entries per page actor.reply(entry); } ``` -------------------------------- ### JSON Translation Example Source: https://github.com/revxrsal/lamp/wiki/Localization-&-Translation Example structure for a JSON file used for localization. ```json { "missing-argument": "No value specified for {0}.", "...": "..." } ``` -------------------------------- ### Register Custom Help Writer Source: https://github.com/revxrsal/lamp/wiki/Command-help Register a custom `CommandHelpWriter` with the `CommandHandler` to define how command help messages are formatted. This example shows a lambda expression for simple string formatting. ```java commandHandler.setHelpWriter((command, actor) -> String.format("%s %s - %s", command.getPath().toRealString(), command.getUsage(), command.getDescription())); ``` -------------------------------- ### CLI Application Integration with CLILamp Source: https://context7.com/revxrsal/lamp/llms.txt Integrate Lamp into CLI applications using CLILamp. Call `lamp.accept(pollStdin())` to start reading from standard input. ```java import revxrsal.commands.Lamp; import revxrsal.commands.cli.CLILamp; import revxrsal.commands.cli.ConsoleActor; import static revxrsal.commands.cli.CLILamp.pollStdin; public class CLIApp { public static void main(String[] args) { Lamp lamp = CLILamp.builder() .responseHandler(String.class, (res, actor, cmd) -> actor.reply(res)) .build(); lamp.register(new FileCommands()); lamp.register(new SystemCommands()); lamp.accept(pollStdin()); // blocks and reads stdin indefinitely } } class FileCommands { @Command("read") public void readFile(ConsoleActor actor, Path file) throws IOException { if (!Files.exists(file)) throw new CommandErrorException("No such file: " + file); Files.readAllLines(file).forEach(actor::reply); } } // Session: // > read notes.txt // Line 1 content // Line 2 content ``` -------------------------------- ### Register Command Hooks in Java Source: https://context7.com/revxrsal/lamp/llms.txt Utilize Lamp's hook system to execute custom logic after command execution or upon command registration. This example logs command executions and registered commands. ```java Lamp lamp = BukkitLamp.builder(this) .hooks(hooks -> { // Called after every successful command execution hooks.onCommandExecuted((command, actor, input) -> getLogger().info(actor.name() + " executed: " + command.usage()) ); // Called when a command is registered hooks.onCommandRegistered(command -> getLogger().fine("Registered command: " + command.usage()) ); }) .build(); ``` -------------------------------- ### Implement Custom Permission System with Annotations in Java Source: https://context7.com/revxrsal/lamp/llms.txt Create custom annotations to define permission requirements and register a permission factory with Lamp to map these annotations to specific permission checks. This example restricts a command to users in the 'admin' group. ```java // Custom annotation for group-based permissions @DistributeOnMethods @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface RequiresGroup { String value(); } ``` ```java // Register a permission factory for the annotation Lamp lamp = BukkitLamp.builder(this) .permissionForAnnotation(RequiresGroup.class, ann -> actor -> GroupManager.getGroup(actor.sender()).equals(ann.value()) ) .build(); ``` ```java // Use the annotation to restrict a command to the "admin" group @RequiresGroup("admin") @Command("admin broadcast") public void broadcast(BukkitCommandActor actor, String message) { Bukkit.broadcastMessage("[ADMIN] " + message); } ``` -------------------------------- ### Handle Supplier Response Source: https://github.com/revxrsal/lamp/wiki/Response-handlers Demonstrates returning a Supplier from a command method. The response handler will process the value obtained by calling Supplier#get(). ```java @Command("hello") public Supplier hello() { return () -> "Hello there!"; // Will send "Hello there!" } ``` -------------------------------- ### Custom JSON Locale Reader Implementation Source: https://github.com/revxrsal/lamp/wiki/Localization-&-Translation An example implementation of a LocaleReader that reads translations from a JSON file. Requires Gson library. ```java import com.google.gson.JsonObject; import com.google.gson.JsonParser; import lombok.SneakyThrows; import revxrsal.commands.locales.LocaleReader; import java.io.BufferedReader; import java.io.File; import java.nio.file.Files; import java.util.Locale; public class JsonLocaleReader implements LocaleReader { private final JsonObject object; private final Locale locale; @SneakyThrows public JsonLocaleReader(File file, Locale locale) { this.locale = locale; try (BufferedReader reader = Files.newBufferedReader(file.toPath())) { object = (JsonObject) JsonParser.parseReader(reader); } } @Override public boolean containsKey(String key) { return object.has(key); } @Override public String get(String key) { return object.getAsJsonPrimitive(key).getAsString(); } @Override public Locale getLocale() { return locale; } } ``` -------------------------------- ### Enum-based ValueResolverFactory Example Source: https://context7.com/revxrsal/lamp/llms.txt Implement a `ParameterType.Factory` for enums to automatically create parsers. This factory respects the `@CaseSensitive` annotation to control case sensitivity during parsing. ```java // Enum-based ValueResolverFactory example (respects @CaseSensitive annotation) public enum EnumResolverFactory implements ParameterType.Factory { INSTANCE; @Override public @Nullable ParameterType create(@NotNull Type type, @NotNull AnnotationList annotations, @NotNull Lamp lamp) { if (!(type instanceof Class) || !((Class) type).isEnum()) return null; Class enumType = ((Class) type).asSubclass(Enum.class); boolean caseSensitive = annotations.contains(CaseSensitive.class); Map> values = new HashMap<>(); for (Enum constant : enumType.getEnumConstants()) values.put(caseSensitive ? constant.name() : constant.name().toLowerCase(), constant); return (input, ctx) -> { String raw = input.readString(); Enum v = values.get(caseSensitive ? raw : raw.toLowerCase()); if (v == null) throw new CommandErrorException("Unknown value: " + raw); return v; }; } } ``` -------------------------------- ### Implement Custom Permission Reader Source: https://github.com/revxrsal/lamp/wiki/Permission-readers Implement the PermissionReader interface to define custom permission logic. This example checks if the current user matches the value specified in the @AccessibleByUser annotation. ```java import revxrsal.commands.command.CommandPermission; import revxrsal.commands.process.PermissionReader; import revxrsal.commands.process.ExecutableCommand; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum UserPermissionReader implements PermissionReader { INSTANCE; @Override public @Nullable CommandPermission getPermission(@NotNull ExecutableCommand command) { AccessibleByUser user = command.getAnnotation(AccessibleByUser.class); if (user == null) { // command does not have @AccessibleByUser return null; } // get the user's name String currentUser = System.getProperty("user.name"); return actor -> currentUser.equals(user.value()); } } ``` -------------------------------- ### Register Custom Parameter Validators in Java Source: https://context7.com/revxrsal/lamp/llms.txt Define custom annotations and register validators with Lamp to enforce specific constraints on command parameters. This example shows validation for positive numbers and existing files. ```java // Custom @Positive annotation @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Positive {} ``` ```java // Custom @FileExists annotation @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface FileExists {} ``` ```java // Register validators during build Lamp lamp = CLILamp.builder() // Number validator: enforce @Positive on any Number subtype .parameterValidator(Number.class, (value, parameter, actor, lamp_) -> { if (parameter.annotations().contains(Positive.class) && value.doubleValue() <= 0) throw new CommandErrorException("Value must be positive! Got: " + value); }) // File validator: enforce @FileExists .parameterValidator(File.class, (file, parameter, actor, lamp_) -> { if (parameter.annotations().contains(FileExists.class) && !file.exists()) throw new CommandErrorException("File does not exist: " + file.getName()); }) .build(); ``` ```java // Usage in commands @Command("sqrt") public void sqrt(ConsoleActor actor, @Positive double value) { actor.reply("√" + value + " = " + Math.sqrt(value)); } ``` -------------------------------- ### Complete build.gradle Configuration for Spigot Plugin with Lamp Source: https://github.com/revxrsal/lamp/wiki/Setting-up This is the complete build.gradle file incorporating all previously mentioned configurations for repositories, dependencies, ShadowJar plugin, and parameter naming. ```groovy plugins { id "com.github.johnrengelman.shadow" version "7.1.2" id "java" } group = "org.example" version = "1.0" sourceCompatibility = 17 targetCompatibility = 17 repositories { mavenCentral() // The JitPack repository, where Lamp is hosted maven { url = "https://jitpack.io/" } // Repositories required for Spigot maven { url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } maven { url = "https://oss.sonatype.org/content/groups/public/" } } dependencies { // The lamp version. This will allow us to easily // update it in the future. def lamp_version = "3.1.8" // Required for all platforms implementation("com.github.Revxrsal.Lamp:common:${lamp_version}") // The Bukkit API for Lamp implementation("com.github.Revxrsal.Lamp:bukkit:${lamp_version}") // The Spigot API compileOnly("org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT") // The adventure API. It may be required at compile-time compileOnly("net.kyori:adventure-platform-bukkit:4.1.2") } // Preserve parameter names in command usage compileJava { options.compilerArgs += ["-parameters"] } ``` -------------------------------- ### Add JitPack and Spigot Repositories to build.gradle Source: https://github.com/revxrsal/lamp/wiki/Setting-up Configure your build.gradle file to include the necessary repositories for fetching Lamp from JitPack and Spigot artifacts. ```groovy repositories { mavenCentral() // The JitPack repository, where Lamp is hosted maven { url = "https://jitpack.io/" } // Repositories required for Spigot maven { url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } maven { url = "https://oss.sonatype.org/content/groups/public/" } } ``` -------------------------------- ### Add Command Description Source: https://github.com/revxrsal/lamp/wiki/Making-our--ban-command-more-robust Use `@Description` to provide a helpful text for the command, visible in `/help`. ```java + @Description("Bans a player and prevents them from joining the server") @CommandPermission("sunbans.command.ban") @Command({"ban", "sunbans ban"}) public void ban(BukkitCommandActor actor, OfflinePlayer target, String reason) { // ... } ``` -------------------------------- ### Create Lamp Instance with BukkitLamp.builder Source: https://context7.com/revxrsal/lamp/llms.txt Use BukkitLamp.builder to create a Lamp instance for Bukkit plugins. Register custom dependencies, parameter types, suggestion providers, and exception handlers before building. ```java import revxrsal.commands.Lamp; import revxrsal.commands.bukkit.BukkitLamp; import revxrsal.commands.bukkit.actor.BukkitCommandActor; import org.bukkit.plugin.java.JavaPlugin; public final class MyPlugin extends JavaPlugin { @Override public void onEnable() { Lamp lamp = BukkitLamp.builder(this) // Register a custom dependency .dependency(QuestManager.class, new QuestManager()) // Register a custom parameter type for Quest objects .parameterTypes(types -> types.addParameterTypeLast(Quest.class, (input, context) -> QuestManager.get(input.readString()))) // Register a suggestion provider for Quest objects .suggestionProviders(suggestions -> suggestions.addProviderLast(Quest.class, (context, actor) -> QuestManager.getNames())) // Custom exception handler .exceptionHandler(new MyExceptionHandler()) // Build the immutable Lamp instance .build(); // Register command classes lamp.register(new QuestCommands()); lamp.register(new AdminCommands()); // Enable Brigadier tab-completion (Minecraft 1.13+) // lamp.accept(BukkitVisitors.brigadier()); } } ``` -------------------------------- ### Build the plugin on Linux/Mac Source: https://github.com/revxrsal/lamp/wiki/Creating-a--hello-command Execute the build command on Linux or macOS systems. This command is equivalent to the gradlew shadowJar command for these operating systems. ```shell ./gradlew shadowJar ``` -------------------------------- ### Basic Command Definition Source: https://github.com/revxrsal/lamp/blob/v4/README.md Defines a simple command named 'greet user' that takes an optional 'name' parameter with a default value of 'World' and replies with a greeting. ```java @Command("greet user") @Description("Sends a greeting message") public void greet(CommandActor actor, @Default("World") String name) { actor.reply("Hello, " + name + "!"); } ``` -------------------------------- ### Implement CommandHelp for Help System Source: https://context7.com/revxrsal/lamp/llms.txt Set a CommandHelpWriter to format command usage strings and use CommandHelp as a command parameter to receive a paginated list of help entries. The help writer formats how each command is displayed in the help output. ```java // Register a help writer that formats command usage strings Lamp lamp = BukkitLamp.builder(this) .build() .accept(lamp2 -> lamp2.setHelpWriter( (command, actor) -> String.format( "&6/%s&7 - &f%s", command.usage(), command.description() != null ? command.description() : "No description" ) )); // Help command that paginates results (7 per page) @Command("plugin help") @Description("Shows all available commands") public void help(BukkitCommandActor actor, CommandHelp help, @Default("1") int page) { List page_ = help.paginate(page, 7); if (page_.isEmpty()) { actor.error("No entries on page " + page); return; } actor.reply("&8=== &6Help &7(Page " + page + "/" + help.pageSize(7) + ")&8 ==="); page_.forEach(actor::reply); } // /plugin help → page 1 // /plugin help 2 → page 2 ``` -------------------------------- ### Apply Custom Permission Annotation to Command Source: https://github.com/revxrsal/lamp/wiki/Permission-readers Apply the custom @AccessibleByUser annotation to a command method to enforce the custom permission check. This example restricts the command to be executable only by the 'root' user. ```java @Command("something dangerous") @AccessibleByUser("root") public void doSomethingDangerous(CommandActor actor) { ... ``` -------------------------------- ### Add Lamp and Spigot Dependencies to build.gradle Source: https://github.com/revxrsal/lamp/wiki/Setting-up Declare the necessary dependencies for Lamp (common and bukkit), Spigot API, and Adventure platform in your build.gradle file. ```groovy dependencies { // The lamp version. This will allow us to easily // update it in the future. def lamp_version = "3.1.8" // Required for all platforms implementation("com.github.Revxrsal.Lamp:common:${lamp_version}") // The Bukkit API for Lamp implementation("com.github.Revxrsal.Lamp:bukkit:${lamp_version}") // The Spigot API. compileOnly("org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT") // The adventure API. It may be required at compile-time compileOnly("net.kyori:adventure-platform-bukkit:4.1.2") } ``` -------------------------------- ### Define Main Plugin Class (Java) Source: https://github.com/revxrsal/lamp/wiki/Creating-the-plugin This Java class serves as the entry point for your plugin. It must extend org.bukkit.plugin.java.JavaPlugin and override onEnable() and onDisable() methods. Mark it as final to prevent accidental extension. ```java package org.example.sunbans; import org.bukkit.plugin.java.JavaPlugin; public final class SunBans extends JavaPlugin { @Override public void onEnable() { } @Override public void onDisable() { } } ``` -------------------------------- ### Build the plugin using ShadowJar Source: https://github.com/revxrsal/lamp/wiki/Creating-a--hello-command Build the plugin JAR file using the ShadowJar Gradle task. This command is used to package your plugin for deployment. ```shell gradlew shadowJar ``` -------------------------------- ### Implement OrphanCommand for Runtime Commands Source: https://context7.com/revxrsal/lamp/llms.txt Implement OrphanCommand for commands whose paths are determined at runtime, such as from configuration files. Use Orphans.path() to supply the command path during registration. ```java public class KitCommand implements OrphanCommand { @Subcommand("give") public void give(CommandActor actor, Kit kit, @Default("me") Player target) { kit.give(target); actor.reply("Gave kit '" + kit.getName() + "' to " + target.getName()); } @Subcommand("list") public void list(CommandActor actor) { Kits.getKitNames().forEach(name -> actor.reply(" - " + name)); } } // In onEnable(), read the command name from config String commandName = getConfig().getString("kit-command", "kit"); lamp.register(Orphans.path(commandName).handler(new KitCommand())); // If commandName = "kit", registers: // /kit give [player] // /kit list ``` -------------------------------- ### Zip File Command Implementation Source: https://github.com/revxrsal/lamp/wiki/Building-commands Implements a command to zip the current directory with optional output file and compression type. ```java public enum Compression { GZIP, ZLIB } @Command("zip pack") public void zipFile( CommandActor actor, @Flag("output") @Optional File output, @Flag("compression") @Default("GZIP") Compression compression ) throws IOException { if (output == null) { // output was not specified File runningDirectory = new File("dummy").getParentFile(); output = new File(runningDirectory, runningDirectory.getName() + ".zip"); } if (output.exists()) throw new CommandErrorException("A file with name '" + output.getName() + "' already exists!"); output.createNewFile(); File directory = output.getParentFile(); // create ZIP here... } ``` -------------------------------- ### Return String Directly from Command Method Source: https://github.com/revxrsal/lamp/wiki/Response-handlers Demonstrates returning a String directly from a command method, which will be automatically handled by the registered String response handler. ```java @Command("hello") public String hello() { return "Hello, world!"; } ``` -------------------------------- ### Initialize BukkitCommandHandler Source: https://github.com/revxrsal/lamp/wiki/Creating-a--hello-command Initialize the BukkitCommandHandler within the onEnable method of your plugin. This is the recommended place for its construction. ```java @Override public void onEnable() { BukkitCommandHandler handler = BukkitCommandHandler.create(this); } ``` -------------------------------- ### JDA (Discord Slash Commands) Integration Source: https://context7.com/revxrsal/lamp/llms.txt Integrate Lamp with Discord bots using JDALamp. Register commands and then call `lamp.accept(slashCommands(jda))` to push them as Discord slash commands. ```java import revxrsal.commands.Lamp; import revxrsal.commands.jda.JDALamp; import revxrsal.commands.jda.actor.SlashCommandActor; import static revxrsal.commands.jda.JDAVisitors.slashCommands; public class DiscordBot { public static void main(String[] args) throws Exception { JDA jda = JDABuilder.createDefault(args[0]).build().awaitReady(); Lamp lamp = JDALamp.builder() .exceptionHandler(new JDAExceptionHandler()) .build(); lamp.register(new ModerationCommands()); // Must be called AFTER all commands are registered lamp.accept(slashCommands(jda)); } } class ModerationCommands { @Command("ban") @Description("Bans the given user") @CommandPermission(Permission.BAN_MEMBERS) // JDA Permission enum public void ban(SlashCommandActor actor, Member target, @Range(min = 1) int days) { actor.replyToInteraction( "User **" + target.getEffectiveName() + "** banned for " + days + " day(s)." ).queue(); } @Command("timeout") @Description("Times out a member") @CommandPermission(Permission.MODERATE_MEMBERS) public void timeout(SlashCommandActor actor, Member target, @Range(min = 1, max = 2419200) int seconds) { target.timeoutFor(seconds, TimeUnit.SECONDS).queue(); actor.replyToInteraction("Timed out **" + target.getEffectiveName() + "** for " + seconds + "s.").queue(); } } ``` -------------------------------- ### Unzip File Command Implementation Source: https://github.com/revxrsal/lamp/wiki/Building-commands Implements a command to unzip files with specified compression type. ```java @Command("zip unpack") public void unzipFile( CommandActor actor, File zipFile, @Flag("compression") @Default("GZIP") Compression compression ) { if (!zipFile.exists()) throw new CommandErrorException("No such file: " + zipFile.getName()); // unpack ZIP here... } ``` -------------------------------- ### Apply ShadowJar Plugin in build.gradle Source: https://github.com/revxrsal/lamp/wiki/Setting-up Apply the ShadowJar plugin to your build.gradle file to ensure Lamp is bundled within your plugin. ```groovy plugins { id "com.github.johnrengelman.shadow" version "7.1.2" // ^^ add this to your plugins {} block id "java" } ``` -------------------------------- ### Implement Reusable Pre-Execution Checks with CommandCondition Source: https://context7.com/revxrsal/lamp/llms.txt Use CommandCondition to define reusable guards that run before command execution. Throw CommandErrorException or SendMessageException to abort. Register conditions before building the Lamp instance. ```java // Custom annotation @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ExecutableOnceInLifetime {} // Condition implementation public enum LifetimeCondition implements CommandCondition { INSTANCE; private final Set executed = Collections.synchronizedSet(new HashSet<>()); @Override public void test(@NotNull CommandActor actor, @NotNull ExecutableCommand command, @NotNull MutableStringStream input) { if (command.annotations().contains(ExecutableOnceInLifetime.class)) { if (!executed.add(actor.uniqueId())) { throw new CommandErrorException("You may only run this command once in your lifetime!"); } } } } // Register the condition before building Lamp Lamp lamp = BukkitLamp.builder(this) .commandCondition(LifetimeCondition.INSTANCE) .build(); // Use the annotation on commands @Command("claim-reward") @ExecutableOnceInLifetime public void claimReward(BukkitCommandActor actor) { actor.reply("You claimed your one-time reward!"); } ``` -------------------------------- ### Registering an Orphan Command Source: https://github.com/revxrsal/lamp/wiki/Orphan-commands Use Orphans.path() to register a command whose path is determined at runtime. The handler method must implement OrphanCommand. ```java CommandHandler handler = ...; handler.register(Orphans.path("path here").handler(OrphanCommand)); ``` -------------------------------- ### Register Kit Class for Parameter Suggestions Source: https://github.com/revxrsal/lamp/wiki/Auto-completions-and-suggestions Register a suggestion provider for a specific parameter type (Kit.class) to automatically suggest registered kit names. This is useful when a parameter consistently maps to a predefined set of values. ```java public final class Kits { private static final Map KITS = new HashMap<>(); public static void register(Kit kit) { KITS.put(kit.getName(), kit); } public static Kit getKit(String name) { return KITS.get(name); } public static Set getKitsNames() { return Collections.unmodifiableSet(KITS.keySet()); } } ``` ```java CommandHandler handler = ...; handler.getAutoCompleter().registerParameterSuggestions(Kit.class, (args, sender, command) -> Kits.getKitsNames()); ``` ```java @Command("kit give") public void giveKit(Kit kit, @Default("me") Player player) { kit.give(player); ... } ``` -------------------------------- ### Localized Descriptions and Responses Source: https://context7.com/revxrsal/lamp/llms.txt Use localized descriptions for commands and localized responses to actors. The #{key} syntax looks up translator keys at runtime. ```java // Localized descriptions (#{key} syntax) @Command("greet") @Description("#{commands.greet.description}") // looks up translator key at runtime public void greet(CommandActor actor) { actor.replyLocalized("commands.greet.response", actor.name()); // Expands: "Welcome, {0}!" → "Welcome, Steve!" } ``` -------------------------------- ### Orphans.path() Syntax Source: https://github.com/revxrsal/lamp/wiki/Orphan-commands Orphans.path() mirrors the syntax of @Command for compile-time known paths and also accepts runtime-determined strings. ```java Orphans.path("foo", "bar") -> @Command("foo", "bar") Orphans.path("foo bar", "buzz boom") -> @Command("foo bar", "buzz boom") ``` -------------------------------- ### Register New Ban Command Source: https://github.com/revxrsal/lamp/wiki/Creating-a-simple--ban-command Registers the newly created `BansCommand` instance with the `BukkitCommandHandler` in the main plugin class. ```java @Override public void onEnable() { BukkitCommandHandler handler = BukkitCommandHandler.create(this); handler.register(new BansCommand()); } ``` -------------------------------- ### Remove Old Hello Command Source: https://github.com/revxrsal/lamp/wiki/Creating-a-simple--ban-command This diff shows how to remove the old `/hello` command from the main plugin class to keep it clean. ```java public final class SunBans extends JavaPlugin { @Override public void onEnable() { BukkitCommandHandler handler = BukkitCommandHandler.create(this); - handler.register(this); } @Override public void onDisable() { } - @Command("hello") - public void sayHello(BukkitCommandActor actor) { - actor.reply("Why, hello there!"); - } } ``` -------------------------------- ### Kotlin Default Arguments Source: https://github.com/revxrsal/lamp/blob/v4/README.md Illustrates using Kotlin's default arguments for optional parameters in a command. The 'target' and 'world' parameters can be omitted. ```kotlin @Command("world") fun teleportToWorld( sender: Player, @Optional target: Player = sender, @Optional world: World = sender.world ) { } ``` -------------------------------- ### Command Aliases Source: https://github.com/revxrsal/lamp/blob/v4/README.md Shows how to create aliases for commands. 'gamemode creative' and 'gmc' both execute the same command to set the player's game mode to creative. ```java @Command({"gamemode creative", "gmc"}) public void creative(@Default("me") Player sender) { sender.setGameMode(GameMode.CREATIVE); } @Command({"gamemode adventure", "gma"}) public void adventure(@Default("me") Player sender) { sender.setGameMode(GameMode.ADVENTURE); } ``` -------------------------------- ### Enable Colorful Command Completions Source: https://github.com/revxrsal/lamp/wiki/Making-our--ban-command-more-robust Call `handler.registerBrigadier()` to enable native-looking command completions for Minecraft 1.13+. ```java @Override public void onEnable() { BukkitCommandHandler handler = BukkitCommandHandler.create(this); handler.register(new BansCommand()); + handler.registerBrigadier(); } ``` -------------------------------- ### Register Suggestion Provider via Factory with Custom Annotation Source: https://context7.com/revxrsal/lamp/llms.txt Implement a suggestion provider factory that uses custom annotations (e.g., `@WithPermission`) on parameters to determine which suggestions to provide. This allows for dynamic suggestion generation based on parameter metadata. ```java // 3. Factory — driven by a custom annotation on the parameter lamp = BukkitLamp.builder(this) .suggestionProviders(s -> s.addProviderFactoryLast( parameter -> { WithPermission ann = parameter.annotations().get(WithPermission.class); if (ann == null) return null; String perm = ann.value(); return (ctx, actor) -> Bukkit.getOnlinePlayers().stream() .filter(p -> p.hasPermission(perm)) .map(Player::getName) .collect(Collectors.toList()); } )) .build(); @Command("send") public void send(CommandActor sender, @WithPermission("hello.lamp") Player player) { // only players with "hello.lamp" are suggested } ``` -------------------------------- ### Custom Parameter Types and Dependencies Source: https://github.com/revxrsal/lamp/blob/v4/README.md Defines a command class 'QuestCommands' with subcommands. It utilizes dependency injection for 'QuestManager' and custom parameter types like 'Quest'. ```kotlin @CommandPermission("quests.command") @Command("quest") class QuestCommands { @Dependency private lateinit var questManager: QuestManager @Subcommand("create") fun createQuest(sender: CommandSender, name: String, description: String) { } @Subcommand(" delete") fun deleteQuest(sender: CommandSender, quest: Quest) { } @Subcommand(" start") fun startQuest(sender: Player, quest: Quest) { } @Subcommand("clear") fun clearQuests(sender: CommandSender) { } } ``` -------------------------------- ### Register String Response Handler using reply() Source: https://github.com/revxrsal/lamp/wiki/Response-handlers A more concise way to register a String response handler by directly referencing the ResponseHandler#reply method. ```java commandHandler.registerResponseHandler(String.class, ResponseHandler::reply); ``` -------------------------------- ### Add Resource Bundles for Localization Source: https://context7.com/revxrsal/lamp/llms.txt Provide translated messages for errors by adding resource bundles. Ensure properties files are in the resources directory. ```java // Create myproject_en.properties in resources: // missing-argument=You must specify a value for {0}. // no-permission=You don't have permission to do that. ``` ```java Lamp lamp = BukkitLamp.builder(this) .build() .accept(l -> l.translator().addResourceBundle("myproject")); ``` -------------------------------- ### Handle CompletableFuture Response Source: https://github.com/revxrsal/lamp/wiki/Response-handlers Shows how to return a CompletableFuture from a command method. The response will be handled once the future resolves its value. ```java @Command("hello") public CompletableFuture hello() { return CompletableFuture.supplyAsync(() -> "Hello there!"); // Will send "Hello there!" after the future resolves } ``` -------------------------------- ### Enable Parameter Naming in build.gradle Source: https://github.com/revxrsal/lamp/wiki/Setting-up Configure the Java compiler arguments in build.gradle to include '-parameters'. This preserves parameter names, enabling Lamp to automatically generate command usages and parameter names. ```groovy compileJava { options.compilerArgs += ["-parameters"] } ``` -------------------------------- ### Configure Command Handler for JSON Source: https://github.com/revxrsal/lamp/wiki/Building-commands Configures the command handler to use '--' as switch prefix and registers a response handler for String type. ```java handler.setSwitchPrefix("--"); handler.registerResponseHandler(String.class, (response, actor, command) -> actor.reply(response)); ``` -------------------------------- ### Multiple Command Variants Source: https://github.com/revxrsal/lamp/blob/v4/README.md Demonstrates defining multiple variants for the 'teleport' command. One variant teleports a target entity to the sender, while another teleports the sender to specified coordinates. ```java @Command("teleport here") public void teleportHere(Player sender, EntitySelector target) { for (LivingEntity entity : target) entity.teleport(sender); } @Command("teleport") public void teleport(Player sender, double x, double y, double z) { sender.teleport(new Location(sender.getWorld(), x, y, z)); } ``` -------------------------------- ### Implement Discord Slash Command in Java Source: https://github.com/revxrsal/lamp/blob/v4/README.md This Java code snippet demonstrates how to implement a Discord slash command using annotations. Ensure JDA and necessary permissions are configured. ```java @Command("ban") @Description("Bans the given user") @CommandPermission(Permission.BAN_MEMBERS) public void ban( SlashCommandActor actor, Member target, @Range(min = 1) int days ) { actor.replyToInteraction("User **" + target.getEffectiveName() + "** has been banned!").queue(); } ``` -------------------------------- ### Inject Dependencies with @Dependency Source: https://context7.com/revxrsal/lamp/llms.txt Inject services into command classes using the @Dependency annotation. Register the dependencies with the Lamp builder using the dependency() method. ```java public class AdminCommands { @Dependency private DatabaseService db; // injected by Lamp @Dependency private PermissionManager perms; // injected by Lamp @Command("userinfo") @CommandPermission("admin.userinfo") public void userInfo(BukkitCommandActor actor, OfflinePlayer target) { UserRecord record = db.getUser(target.getUniqueId()); if (record == null) { actor.error("No record found for " + target.getName()); return; } actor.reply("User: " + record.getName() + " | Rank: " + perms.getRank(record)); } } // Register dependencies during build: DatabaseService dbService = new DatabaseService(getConfig()); Lamp lamp = BukkitLamp.builder(this) .dependency(DatabaseService.class, dbService) .dependency(PermissionManager.class, new PermissionManager()) .build(); lamp.register(new AdminCommands()); ``` -------------------------------- ### Handle Optional.empty() Response Source: https://github.com/revxrsal/lamp/wiki/Response-handlers Shows how returning an empty Optional from a command method results in no response being sent to the actor. ```java @Command("hello") public Optional hello() { return Optional.empty(); // nothing will be sent } ``` -------------------------------- ### Registering a Resource Bundle Source: https://github.com/revxrsal/lamp/wiki/Localization-&-Translation Register a custom resource bundle for localization. By default, all language locales are registered. ```java commandHandler.getTranslator().addResourceBundle("myproject"); ``` -------------------------------- ### Format JSON Command Implementation Source: https://github.com/revxrsal/lamp/wiki/Building-commands Implements a command to format JSON strings with options for pretty-printing and disabling HTML escaping. ```java @Command("formatjson") public String formatJSON( String json, @Switch("pretty-printing") boolean prettyPrinting, @Switch("disable-html-escaping") boolean disableHtmlEscaping ) { GsonBuilder builder = new GsonBuilder(); if (prettyPrinting) builder.setPrettyPrinting(); if (disableHtmlEscaping) builder.disableHtmlEscaping(); Gson gson = builder.create(); JsonElement element = JsonParser.parseString(json); return gson.toJson(element); } ``` -------------------------------- ### Define Ban Command Structure Source: https://github.com/revxrsal/lamp/wiki/Creating-a-simple--ban-command Defines the structure for the ban command, including aliases and method parameters that Lamp automatically parses. ```java public class BansCommand { @Command({"ban", "sunbans ban"}) public void ban( BukkitCommandActor actor, OfflinePlayer target, String reason ) { } } ``` -------------------------------- ### Register Suggestion Provider by Parameter Type Source: https://context7.com/revxrsal/lamp/llms.txt Register a suggestion provider that applies to all parameters of a specific type, such as `Quest`. This allows for type-specific tab-completion logic. ```java // 1. Suggest by parameter type — all Quest parameters get quest-name completions lamp = BukkitLamp.builder(this) .suggestionProviders(s -> s.addProviderLast(Quest.class, (context, actor) -> QuestManager.getNames())) .build(); ``` -------------------------------- ### Read File Command Source: https://github.com/revxrsal/lamp/wiki/Building-commands A command that reads and replies with all lines from a given file. It includes error handling for non-existent files. ```java @Command("read") public void readFile(CommandActor actor, Path file) throws IOException { if (!Files.exists(file)) throw new CommandErrorException("No such file: " + file); Files.readAllLines(file).forEach(actor::reply); } ``` -------------------------------- ### Implement Ban Command Logic Source: https://github.com/revxrsal/lamp/wiki/Creating-a-simple--ban-command Adds the core logic to ban a player using Bukkit's BanList API and provides feedback to the actor. ```java @Command({"ban", "sunbans ban"}) public void ban(BukkitCommandActor actor, OfflinePlayer target, String reason) { Bukkit.getBanList(BanList.Type.NAME) .addBan( /* target = */ target.getName(), /* reason = */ reason, /* expires = */ null, /* source = */ actor.getName() ); actor.reply("&aSuccessfully banned &e" + target.getName() + "&a!"); } ``` -------------------------------- ### Handle Optional Parameters with @Optional and @Default Source: https://context7.com/revxrsal/lamp/llms.txt Mark parameters as optional using @Optional, which defaults to null or zero when absent. Use @Default to provide a fallback string value. ```java @Command({"gamemode", "gm"}) @Description("Change your gamemode") public class GamemodeCommand { // /gamemode creative [player] — player defaults to the sender @Subcommand("creative") public void creative(@Default("me") Player target) { target.setGameMode(GameMode.CREATIVE); } // /ban [reason] [duration] @Command("ban") public void ban( BukkitCommandActor actor, OfflinePlayer target, @Default("No reason provided") String reason, @Optional @Nullable Duration duration // null when omitted ) { Date expiry = (duration != null) ? Date.from(Instant.now().plus(duration)) : null; Bukkit.getBanList(BanList.Type.NAME).addBan(target.getName(), reason, expiry, actor.getName()); actor.reply("Banned " + target.getName()); } } ``` -------------------------------- ### Handle Optional.of() Response Source: https://github.com/revxrsal/lamp/wiki/Response-handlers Illustrates returning a value wrapped in Optional from a command method, which will be handled by the registered response handler. ```java @Command("hello") public Optional hello() { return Optional.of("Hello there!"); // Will send "Hello there!" } ``` -------------------------------- ### Command with Error Source: https://github.com/revxrsal/lamp/wiki/Exceptions This command is designed to intentionally throw an ArithmeticException to demonstrate error handling and stack trace sanitization. ```java @Command("error") public void alwaysError() { System.out.println(1 / 0); } ``` -------------------------------- ### Plugin Descriptor File (plugin.yml) Source: https://github.com/revxrsal/lamp/wiki/Creating-the-plugin The plugin.yml file is essential for Minecraft to recognize your plugin. It specifies the plugin's name, main class, description, version, and the compatible API version. ```yaml name: SunBans main: org.example.sunbans.SunBans description: A simple punishment plugin version: 1.0 api-version: 1.13 ``` -------------------------------- ### Implementing an Orphan Command Source: https://github.com/revxrsal/lamp/wiki/Orphan-commands Define a class that implements OrphanCommand and use the @Subcommand annotation for its methods. ```java public class Foo implements OrphanCommand { @Subcommand("bar") public void bar(CommandActor actor) { actor.reply("Hello!"); } } ``` -------------------------------- ### Define Commands with Switches and Flags Source: https://context7.com/revxrsal/lamp/llms.txt Use @Switch for boolean flags and @Flag for named value parameters. Supports shorthand flag combinations. ```java @Command("formatjson") public String formatJSON( CommandActor actor, String json, @Switch("pretty-printing") boolean prettyPrinting, // --pretty-printing or -p @Switch("disable-html-escaping") boolean disableHtmlEscaping // --disable-html-escaping or -d ) { GsonBuilder builder = new GsonBuilder(); if (prettyPrinting) builder.setPrettyPrinting(); if (disableHtmlEscaping) builder.disableHtmlEscaping(); return builder.create().toJson(JsonParser.parseString(json)); } // Usage: // > formatjson [1,2,3] → [1,2,3] // > formatjson [1,2,3] --pretty-printing → prettified JSON // > formatjson [1,2,3] -pd → pretty + no HTML escaping @Command("zip pack") public void zip( CommandActor actor, @Flag("output") @Optional File output, // --output foo.zip @Flag("compression") @Default("GZIP") Compression compression // --compression ZLIB ) { // output is null when not specified if (output == null) output = new File("archive.zip"); // compress here... actor.reply("Packed to " + output.getName() + " using " + compression); } ``` -------------------------------- ### Echo Command with String Return Source: https://github.com/revxrsal/lamp/wiki/Building-commands A simple echo command that returns the input message. The registered String response handler will automatically send this to the actor. ```java @Command({"ping", "echo"}) public String echo(@Default("") String message) { return message; } ``` -------------------------------- ### Echo Command with Actor Reply Source: https://github.com/revxrsal/lamp/wiki/Building-commands An echo command that directly replies to the actor with the provided message. This is an alternative to returning a String. ```java @Command({"ping", "echo"}) public void echo(CommandActor actor, @Default("") String message) { actor.reply(message); } ``` -------------------------------- ### Add Command Permission Source: https://github.com/revxrsal/lamp/wiki/Making-our--ban-command-more-robust Use `@CommandPermission` to restrict command execution to players with the specified permission. ```java + @CommandPermission("sunbans.command.ban") @Command({"ban", "sunbans ban"}) public void ban(BukkitCommandActor actor, OfflinePlayer target, String reason) { // ... } ``` -------------------------------- ### Implement Manual Cooldown with CooldownHandle Source: https://context7.com/revxrsal/lamp/llms.txt Use CooldownHandle for fine-grained control over cooldowns. Allows checking and applying cooldowns conditionally. ```java // Manual cooldown via CooldownHandle — conditionally apply cooldown @Command("risky") public void risky( Player player, @Cooldown(value = 5, unit = TimeUnit.MINUTES) CooldownHandle handle ) { handle.requireNotOnCooldown(); // throws CooldownException if still cooling down boolean success = attemptRiskyAction(player); if (success) { handle.cooldown(); // only start cooldown on success } // To check remaining time: // long seconds = handle.remainingTime(TimeUnit.SECONDS); } ``` -------------------------------- ### Declaring Commands with @Command and @Subcommand Source: https://context7.com/revxrsal/lamp/llms.txt Annotate methods or classes with @Command to register them. Use @Subcommand for nested commands. Spaces in the value create subcommand paths, and multiple values define aliases. Class-level @Command prefixes all @Subcommand methods within. ```java import revxrsal.commands.annotation.*; import revxrsal.commands.bukkit.actor.BukkitCommandActor; @Command("punishment") // class-level prefix @Description("Punishment management") public class PunishmentCommands { // /punishment ban [reason] @Subcommand("ban") @Description("Bans a player from the server") @CommandPermission("punishments.ban") // platform-specific annotation public void ban( BukkitCommandActor actor, OfflinePlayer target, @Default("No reason provided") String reason // greedy; consumes rest of input ) { Bukkit.getBanList(BanList.Type.NAME) .addBan(target.getName(), reason, null, actor.getName()); actor.reply("&aBanned &e" + target.getName() + "&a: " + reason); } // /punishment kick OR /pk (alias) @Command({"punishment kick", "pk"}) public void kick(Player sender, Player target) { target.kickPlayer("Kicked by " + sender.getName()); } } // Registration in onEnable(): // Lamp lamp = BukkitLamp.builder(this).build(); // lamp.register(new PunishmentCommands()); ``` -------------------------------- ### Make Reason Parameter Optional Source: https://github.com/revxrsal/lamp/wiki/Making-our--ban-command-more-robust Annotate a parameter with `@Optional` to allow the command to be executed without providing a value for it. The parameter will be `null` if not provided. ```java @Description("Bans a player by preventing them from joining the server") @CommandPermission("sunbans.command.ban") @Command({"ban", "sunbans ban"}) public void ban( BukkitCommandActor actor, OfflinePlayer target, + @Optional String reason ) { // ... } ``` -------------------------------- ### Register SuggestionProviderFactory with Custom Logic Source: https://github.com/revxrsal/lamp/wiki/Auto-completions-and-suggestions Register a SuggestionProviderFactory as a lambda expression to handle auto-completions based on custom annotations. This factory checks for the @WithPermission annotation and provides a list of players who have the specified permission. ```java import java.util.ArrayList; import java.util.List; import org.bukkit.Bukkit; import org.bukkit.entity.Player; handler.getAutoCompleter().registerSuggestionFactory(parameter -> { if (parameter.hasAnnotation(WithPermission.class)) { String permission = parameter.getAnnotation(WithPermission.class).value(); return (args, sender, command) -> { // Create a SuggestionProvider here List players = new ArrayList<>(); for (Player player : Bukkit.getOnlinePlayers()) { if (player.hasPermission(permission)) players.add(player.getName()); } return players; }; } return null; // Parameter does not have @WithPermission, ignore it. }); ```