|
25 | 25 | package de.bluecolored.bluemap.bukkit; |
26 | 26 |
|
27 | 27 | import java.util.ArrayList; |
28 | | -import java.util.Arrays; |
29 | 28 | import java.util.Collection; |
30 | | -import java.util.UUID; |
| 29 | +import java.util.List; |
| 30 | +import java.util.concurrent.ExecutionException; |
| 31 | +import java.util.concurrent.TimeUnit; |
| 32 | +import java.util.concurrent.TimeoutException; |
31 | 33 |
|
32 | | -import org.bukkit.Bukkit; |
33 | | -import org.bukkit.World; |
34 | | -import org.bukkit.command.CommandExecutor; |
| 34 | +import org.apache.commons.lang.StringUtils; |
| 35 | +import org.bukkit.ChatColor; |
35 | 36 | import org.bukkit.command.CommandSender; |
36 | | -import org.bukkit.entity.Player; |
| 37 | +import org.bukkit.command.defaults.BukkitCommand; |
| 38 | +import org.bukkit.event.EventHandler; |
| 39 | +import org.bukkit.event.Listener; |
| 40 | +import org.bukkit.event.server.TabCompleteEvent; |
37 | 41 |
|
38 | | -import com.flowpowered.math.vector.Vector2i; |
39 | | -import com.flowpowered.math.vector.Vector3i; |
| 42 | +import com.mojang.brigadier.CommandDispatcher; |
| 43 | +import com.mojang.brigadier.exceptions.CommandSyntaxException; |
| 44 | +import com.mojang.brigadier.suggestion.Suggestion; |
| 45 | +import com.mojang.brigadier.suggestion.Suggestions; |
| 46 | +import com.mojang.brigadier.tree.CommandNode; |
40 | 47 |
|
41 | | -import de.bluecolored.bluemap.common.plugin.Commands; |
42 | | -import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource; |
43 | | -import de.bluecolored.bluemap.common.plugin.text.Text; |
44 | | -import de.bluecolored.bluemap.common.plugin.text.TextColor; |
| 48 | +import de.bluecolored.bluemap.common.plugin.Plugin; |
| 49 | +import de.bluecolored.bluemap.common.plugin.commands.Commands; |
45 | 50 |
|
46 | | -public class BukkitCommands implements CommandExecutor { |
47 | | - |
48 | | - private Commands bluemapCommands; |
49 | | - |
50 | | - private Collection<Command> commands; |
| 51 | +public class BukkitCommands implements Listener { |
| 52 | + |
| 53 | + private CommandDispatcher<CommandSender> dispatcher; |
51 | 54 |
|
52 | | - public BukkitCommands(Commands commands) { |
53 | | - this.bluemapCommands = commands; |
54 | | - this.commands = new ArrayList<>(); |
55 | | - initCommands(); |
| 55 | + public BukkitCommands(final Plugin plugin) { |
| 56 | + this.dispatcher = new CommandDispatcher<>(); |
| 57 | + |
| 58 | + // register commands |
| 59 | + new Commands<>(plugin, dispatcher, bukkitSender -> new BukkitCommandSource(plugin, bukkitSender)); |
56 | 60 | } |
57 | 61 |
|
58 | | - private void initCommands() { |
59 | | - |
60 | | - commands.add(new Command("bluemap.status") { |
61 | | - @Override |
62 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
63 | | - if (args.length != 0) return false; |
64 | | - |
65 | | - bluemapCommands.executeRootCommand(source); |
66 | | - return true; |
67 | | - } |
68 | | - }); |
69 | | - |
70 | | - commands.add(new Command("bluemap.reload", "reload") { |
71 | | - @Override |
72 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
73 | | - if (args.length != 0) return false; |
74 | | - |
75 | | - bluemapCommands.executeReloadCommand(source); |
76 | | - return true; |
77 | | - } |
78 | | - }); |
79 | | - |
80 | | - commands.add(new Command("bluemap.pause", "pause") { |
81 | | - @Override |
82 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
83 | | - if (args.length != 0) return false; |
84 | | - |
85 | | - bluemapCommands.executePauseCommand(source); |
86 | | - return true; |
87 | | - } |
88 | | - }); |
| 62 | + public Collection<BukkitCommand> getRootCommands(){ |
| 63 | + Collection<BukkitCommand> rootCommands = new ArrayList<>(); |
89 | 64 |
|
90 | | - commands.add(new Command("bluemap.resume", "resume") { |
91 | | - @Override |
92 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
93 | | - if (args.length != 0) return false; |
94 | | - |
95 | | - bluemapCommands.executeResumeCommand(source); |
96 | | - return true; |
97 | | - } |
98 | | - }); |
| 65 | + for (CommandNode<CommandSender> node : this.dispatcher.getRoot().getChildren()) { |
| 66 | + rootCommands.add(new CommandProxy(node.getName())); |
| 67 | + } |
99 | 68 |
|
100 | | - commands.add(new Command("bluemap.render", "render") { |
101 | | - @Override |
102 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
103 | | - if (sender instanceof Player) { |
104 | | - if (args.length > 2) return false; |
105 | | - Player player = (Player) sender; |
106 | | - |
107 | | - World world = null; |
108 | | - int radius = -1; |
109 | | - if (args.length >= 1) { |
110 | | - world = Bukkit.getWorld(args[0]); |
111 | | - } |
112 | | - if (args.length == 2 || (args.length == 1 && world == null)) { |
113 | | - try { |
114 | | - radius = Integer.parseInt(args[args.length - 1]); |
115 | | - } catch (NumberFormatException ex) { |
116 | | - return false; |
117 | | - } |
118 | | - } |
119 | | - if (world == null){ |
120 | | - world = player.getWorld(); |
121 | | - } |
122 | | - |
123 | | - if (radius >= 0) { |
124 | | - Vector2i pos = new Vector2i(player.getLocation().getBlockX(), player.getLocation().getBlockZ()); |
125 | | - bluemapCommands.executeRenderWorldCommand(source, world.getUID(), pos, radius); |
126 | | - } else { |
127 | | - bluemapCommands.executeRenderWorldCommand(source, world.getUID()); |
128 | | - } |
129 | | - return true; |
130 | | - } else { |
131 | | - if (args.length != 1) return false; |
132 | | - World world = Bukkit.getWorld(args[0]); |
| 69 | + return rootCommands; |
| 70 | + } |
| 71 | + |
| 72 | + @EventHandler |
| 73 | + public void onTabComplete(TabCompleteEvent evt) { |
| 74 | + try { |
| 75 | + Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(evt.getBuffer().substring(1), evt.getSender())).get(100, TimeUnit.MILLISECONDS); |
| 76 | + List<String> completions = new ArrayList<>(); |
| 77 | + for (Suggestion suggestion : suggestions.getList()) { |
| 78 | + String text = suggestion.getText(); |
133 | 79 |
|
134 | | - bluemapCommands.executeRenderWorldCommand(source, world.getUID()); |
135 | | - return true; |
136 | | - } |
137 | | - } |
138 | | - }); |
139 | | - |
140 | | - commands.add(new Command("bluemap.render", "render", "prioritize") { |
141 | | - @Override |
142 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
143 | | - if (args.length != 1) return false; |
144 | | - |
145 | | - try { |
146 | | - UUID uuid = UUID.fromString(args[0]); |
147 | | - bluemapCommands.executePrioritizeRenderTaskCommand(source, uuid); |
148 | | - return true; |
149 | | - } catch (IllegalArgumentException ex) { |
150 | | - source.sendMessage(Text.of(TextColor.RED, "'" + args[0] + "' is not a valid UUID!")); |
151 | | - return true; |
152 | | - } |
153 | | - } |
154 | | - }); |
155 | | - |
156 | | - commands.add(new Command("bluemap.render", "render", "remove") { |
157 | | - @Override |
158 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
159 | | - if (args.length != 1) return false; |
160 | | - |
161 | | - try { |
162 | | - UUID uuid = UUID.fromString(args[0]); |
163 | | - bluemapCommands.executeRemoveRenderTaskCommand(source, uuid); |
164 | | - return true; |
165 | | - } catch (IllegalArgumentException ex) { |
166 | | - source.sendMessage(Text.of(TextColor.RED, "'" + args[0] + "' is not a valid UUID!")); |
167 | | - return true; |
| 80 | + if (text.indexOf(' ') == -1) { |
| 81 | + completions.add(text); |
168 | 82 | } |
169 | 83 | } |
170 | | - }); |
171 | | - |
172 | | - commands.add(new Command("bluemap.debug", "debug") { |
173 | | - @Override |
174 | | - public boolean execute(CommandSender sender, CommandSource source, String[] args) { |
175 | | - if (!(sender instanceof Player)) { |
176 | | - source.sendMessage(Text.of(TextColor.RED, "You have to be a player to use this command!")); |
177 | | - return true; |
178 | | - } |
179 | | - |
180 | | - Player player = (Player) sender; |
181 | | - UUID world = player.getWorld().getUID(); |
182 | | - Vector3i pos = new Vector3i( |
183 | | - player.getLocation().getBlockX(), |
184 | | - player.getLocation().getBlockY(), |
185 | | - player.getLocation().getBlockZ() |
186 | | - ); |
187 | | - |
188 | | - bluemapCommands.executeDebugCommand(source, world, pos); |
189 | | - return true; |
| 84 | + |
| 85 | + if (!completions.isEmpty()) { |
| 86 | + completions.sort((s1, s2) -> s1.compareToIgnoreCase(s2)); |
| 87 | + evt.setCompletions(completions); |
190 | 88 | } |
191 | | - }); |
192 | | - |
| 89 | + } catch (InterruptedException | ExecutionException | TimeoutException ignore) {} |
193 | 90 | } |
| 91 | + |
| 92 | + private class CommandProxy extends BukkitCommand { |
194 | 93 |
|
195 | | - @Override |
196 | | - public boolean onCommand(CommandSender sender, org.bukkit.command.Command bukkitCommand, String label, String[] args) { |
197 | | - int max = -1; |
198 | | - Command maxCommand = null; |
199 | | - for (Command command : commands) { |
200 | | - int matchSize = command.matches(args); |
201 | | - if (matchSize > max) { |
202 | | - maxCommand = command; |
203 | | - max = matchSize; |
204 | | - } |
205 | | - } |
206 | | - |
207 | | - if (maxCommand == null) return false; |
208 | | - |
209 | | - BukkitCommandSource source = new BukkitCommandSource(sender); |
210 | | - |
211 | | - if (!maxCommand.checkPermission(sender)) { |
212 | | - source.sendMessage(Text.of(TextColor.RED, "You don't have permission to use this command!")); |
213 | | - return true; |
| 94 | + protected CommandProxy(String name) { |
| 95 | + super(name); |
214 | 96 | } |
215 | | - |
216 | | - return maxCommand.execute(sender, source, Arrays.copyOfRange(args, max, args.length)); |
217 | | - } |
218 | 97 |
|
219 | | - private abstract class Command { |
220 | | - |
221 | | - private String[] command; |
222 | | - private String permission; |
223 | | - |
224 | | - public Command(String permission, String... command) { |
225 | | - this.command = command; |
226 | | - } |
227 | | - |
228 | | - public abstract boolean execute(CommandSender sender, CommandSource source, String[] args); |
229 | | - |
230 | | - public int matches(String[] args) { |
231 | | - if (args.length < command.length) return -1; |
232 | | - |
233 | | - for (int i = 0; i < command.length; i++) { |
234 | | - if (!args[i].equalsIgnoreCase(command[i])) return -1; |
| 98 | + @Override |
| 99 | + public boolean execute(CommandSender sender, String commandLabel, String[] args) { |
| 100 | + String command = commandLabel; |
| 101 | + if (args.length > 0) { |
| 102 | + command += " " + StringUtils.join(args, ' '); |
235 | 103 | } |
236 | 104 |
|
237 | | - return command.length; |
238 | | - } |
239 | | - |
240 | | - public boolean checkPermission(CommandSender sender) { |
241 | | - if (sender.isOp()) return true; |
242 | | - return sender.hasPermission(permission); |
| 105 | + try { |
| 106 | + return dispatcher.execute(command, sender) > 0; |
| 107 | + } catch (CommandSyntaxException ex) { |
| 108 | + sender.sendMessage(ChatColor.RED + ex.getRawMessage().getString()); |
| 109 | + |
| 110 | + String context = ex.getContext(); |
| 111 | + if (context != null) sender.sendMessage(ChatColor.GRAY + context); |
| 112 | + |
| 113 | + return false; |
| 114 | + } |
243 | 115 | } |
244 | 116 |
|
245 | 117 | } |
|
0 commit comments