001/* 002 * Copyright 2021 Siroshun09 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.github.siroshun09.mccommand.bukkit; 018 019import com.github.siroshun09.mccommand.bukkit.sender.BukkitSender; 020import com.github.siroshun09.mccommand.common.Command; 021import com.github.siroshun09.mccommand.common.context.CommandContext; 022import com.github.siroshun09.mccommand.common.context.SimpleCommandContext; 023import net.kyori.adventure.platform.bukkit.BukkitAudiences; 024import org.bukkit.command.CommandExecutor; 025import org.bukkit.command.CommandSender; 026import org.bukkit.command.PluginCommand; 027import org.bukkit.command.TabCompleter; 028import org.bukkit.plugin.Plugin; 029import org.bukkit.plugin.java.JavaPlugin; 030import org.jetbrains.annotations.NotNull; 031import org.jetbrains.annotations.Nullable; 032 033import java.util.List; 034import java.util.concurrent.Executor; 035import java.util.concurrent.Executors; 036 037/** 038 * The class for registering commands to Bukkit. 039 */ 040public final class BukkitCommandFactory { 041 042 private BukkitCommandFactory() { 043 throw new UnsupportedOperationException(); 044 } 045 046 /** 047 * Registers the command. 048 * 049 * @param target the {@link PluginCommand} 050 * @param command the command to register 051 */ 052 public static void register(@NotNull PluginCommand target, @NotNull Command command) { 053 BukkitCommandImpl bukkitCommand = new BukkitCommandImpl(target.getPlugin(), command); 054 055 target.setExecutor(bukkitCommand); 056 target.setTabCompleter(bukkitCommand); 057 } 058 059 /** 060 * Searches for {@link PluginCommand} that is named as {@link Command#getName()} 061 * and register the command if it exists. 062 * 063 * @param sourcePlugin the plugin to search for the command 064 * @param command the command to register 065 */ 066 public static void registerIfExists(@NotNull JavaPlugin sourcePlugin, @NotNull Command command) { 067 PluginCommand pluginCommand = sourcePlugin.getCommand(command.getName()); 068 069 if (pluginCommand != null) { 070 register(pluginCommand, command); 071 } 072 } 073 074 /** 075 * Registers the command. 076 * <p> 077 * If you register a command with this method, it will be executed asynchronously. 078 * <p> 079 * Note: 080 * <p> 081 * The tab completion will execute on main thread. 082 * 083 * @param target the {@link PluginCommand} 084 * @param command the command to register 085 */ 086 public static void registerAsync(@NotNull PluginCommand target, @NotNull Command command) { 087 registerAsync(target, command, Executors.newSingleThreadExecutor()); 088 } 089 090 /** 091 * Searches for {@link PluginCommand} that is named as {@link Command#getName()} 092 * and register the command if it exists. 093 * 094 * @param sourcePlugin the plugin to search for the command 095 * @param command the command to register 096 * @see BukkitCommandFactory#registerAsync(PluginCommand, Command) 097 */ 098 public static void registerAsyncIfExists(@NotNull JavaPlugin sourcePlugin, @NotNull Command command) { 099 PluginCommand pluginCommand = sourcePlugin.getCommand(command.getName()); 100 101 if (pluginCommand != null) { 102 registerAsync(pluginCommand, command); 103 } 104 } 105 106 /** 107 * Registers the command. 108 * <p> 109 * If you register a command with this method, it will be executed asynchronously. 110 * <p> 111 * Note: 112 * <p> 113 * The tab completion will execute on main thread. 114 * 115 * @param target the {@link PluginCommand} 116 * @param command the command to register 117 * @param executor the executor to run command 118 */ 119 public static void registerAsync(@NotNull PluginCommand target, @NotNull Command command, @NotNull Executor executor) { 120 AsyncBukkitCommandImpl bukkitCommand = new AsyncBukkitCommandImpl(target.getPlugin(), command, executor); 121 122 target.setExecutor(bukkitCommand); 123 target.setTabCompleter(bukkitCommand); 124 } 125 126 /** 127 * Searches for {@link PluginCommand} that is named as {@link Command#getName()} 128 * and register the command if it exists. 129 * 130 * @param sourcePlugin the plugin to search for the command 131 * @param command the command to register 132 * @param executor the executor to run command 133 * @see BukkitCommandFactory#registerAsync(PluginCommand, Command) 134 */ 135 public static void registerAsyncIfExists(@NotNull JavaPlugin sourcePlugin, @NotNull Command command, 136 @NotNull Executor executor) { 137 PluginCommand pluginCommand = sourcePlugin.getCommand(command.getName()); 138 139 if (pluginCommand != null) { 140 registerAsync(pluginCommand, command, executor); 141 } 142 } 143 144 private static class BukkitCommandImpl implements CommandExecutor, TabCompleter { 145 146 private final BukkitAudiences audiences; 147 private final Command command; 148 149 private BukkitCommandImpl(@NotNull Plugin plugin, @NotNull Command command) { 150 this.audiences = BukkitAudiences.create(plugin); 151 this.command = command; 152 } 153 154 @Override 155 public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd, 156 @NotNull String label, @NotNull String[] args) { 157 command.onExecution( 158 createContext(sender, label, args) 159 ); 160 161 return true; 162 } 163 164 @Override 165 public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd, 166 @NotNull String label, @NotNull String[] args) { 167 return command.onTabCompletion( 168 createContext(sender, label, args) 169 ); 170 } 171 172 private CommandContext createContext(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { 173 return SimpleCommandContext.newBuilder() 174 .setCommand(command) 175 .setSender(new BukkitSender(audiences, sender)) 176 .setArguments(args) 177 .setLabel(label) 178 .build(); 179 } 180 } 181 182 private static class AsyncBukkitCommandImpl implements CommandExecutor, TabCompleter { 183 184 private final BukkitAudiences audiences; 185 private final Command command; 186 private final Executor executor; 187 188 private AsyncBukkitCommandImpl(@NotNull Plugin plugin, @NotNull Command command, @NotNull Executor executor) { 189 this.audiences = BukkitAudiences.create(plugin); 190 this.command = command; 191 this.executor = executor; 192 } 193 194 @Override 195 public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd, 196 @NotNull String label, @NotNull String[] args) { 197 executor.execute(() -> 198 command.onExecution( 199 createContext(sender, label, args) 200 )); 201 202 return true; 203 } 204 205 @Override 206 public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd, 207 @NotNull String label, @NotNull String[] args) { 208 return command.onTabCompletion( 209 createContext(sender, label, args) 210 ); 211 } 212 213 private CommandContext createContext(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { 214 return SimpleCommandContext.newBuilder() 215 .setCommand(command) 216 .setSender(new BukkitSender(audiences, sender)) 217 .setArguments(args) 218 .setLabel(label) 219 .build(); 220 } 221 } 222}