/
CommandScriptHelper.java
166 lines (150 loc) · 7.03 KB
/
CommandScriptHelper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package net.aufdemrand.denizen.scripts.containers.core;
import com.google.common.base.Predicate;
import net.aufdemrand.denizen.Settings;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.DenizenAliasHelpTopic;
import net.aufdemrand.denizen.utilities.DenizenCommand;
import net.aufdemrand.denizen.utilities.DenizenCommandHelpTopic;
import net.aufdemrand.denizen.utilities.debugging.dB;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.command.defaults.HelpCommand;
import org.bukkit.event.Listener;
import org.bukkit.help.HelpMap;
import org.bukkit.help.HelpTopic;
import org.bukkit.scheduler.BukkitRunnable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class CommandScriptHelper implements Listener {
private static Map<String, DenizenCommand> denizenCommands = new ConcurrentHashMap<String, DenizenCommand>(8, 0.9f, 1);
private static Map<String, Command> overriddenCommands = new HashMap<String, Command>();
private static Map<String, HelpTopic> overriddenHelpTopics = new HashMap<String, HelpTopic>();
private static Map<String, Command> knownCommands = null;
private static Map<String, HelpTopic> helpTopics = null;
private static boolean hasCommandInformation = true;
public CommandScriptHelper() {
try {
final Server server = DenizenAPI.getCurrentInstance().getServer();
server.getPluginManager().registerEvents(this, DenizenAPI.getCurrentInstance());
// Get the CommandMap for the server
final Field commandMapField = server.getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);
CommandMap commandMap = (CommandMap) commandMapField.get(server);
// Get the knownCommands for the server's CommandMap
final Field knownCommandsField = commandMap.getClass().getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true);
knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap);
// Get the HelpMap for the server
HelpMap helpMap = server.getHelpMap();
// Get the helpTopics for the server's HelpMap
final Field helpTopicsField = helpMap.getClass().getDeclaredField("helpTopics");
helpTopicsField.setAccessible(true);
helpTopics = (Map<String, HelpTopic>) helpTopicsField.get(helpMap);
// The Minecraft Help command doesn't like our added commands,
// so let's force the server to use Bukkit's version if it's running
// Mojang's version.
// TODO: figure out a different workaround?
if (Settings.overrideHelp()) {
new BukkitRunnable() {
@Override
public void run() {
if (knownCommands.get("help") instanceof HelpCommand) {
return;
}
knownCommands.put("help", knownCommands.get("bukkit:help"));
helpTopics.put("/help", helpTopics.get("/bukkit:help"));
}
}.runTaskLater(DenizenAPI.getCurrentInstance(), 1);
}
}
catch (Exception e) {
dB.echoError("Error getting the server's command information! Are you running a non-CraftBukkit server?");
dB.echoError("Command scripts will not function!");
//dB.echoError(e);
hasCommandInformation = false;
}
}
/**
* Removes all registered {@link DenizenCommand DenizenCommands} from CraftBukkit and restores any
* overridden Commands.
*
* @see #registerDenizenCommand(DenizenCommand)
*/
public static void removeDenizenCommands() {
if (!hasCommandInformation) {
return;
}
for (String command : denizenCommands.keySet()) {
knownCommands.remove(command);
helpTopics.remove(command);
if (overriddenCommands.containsKey(command)) {
knownCommands.put(command, overriddenCommands.get(command));
if (overriddenHelpTopics.containsKey(command)) {
helpTopics.put(command, overriddenHelpTopics.get(command));
}
}
}
denizenCommands.clear();
}
/**
* Registers a {@link DenizenCommand} to CraftBukkit, including aliases and help command
* information. This will override any existing command aliases or names.
*
* @param command the command to register.
* @see #removeDenizenCommands()
*/
public static void registerDenizenCommand(DenizenCommand command) {
if (!hasCommandInformation) {
return;
}
String name = command.getName();
// Existing Denizen commands take priority!
if (!denizenCommands.containsKey(name)) {
// Register the command
forceCommand(name, command, new DenizenCommandHelpTopic(command));
// Register each alias
for (String alias : command.getAliases()) {
if (denizenCommands.containsKey(alias)) {
continue;
}
forceCommand(alias, command, new DenizenAliasHelpTopic("/" + alias, name,
DenizenAPI.getCurrentInstance().getServer().getHelpMap()));
}
}
}
/**
* Forces CraftBukkit to recognize DenizenCommands, and overrides any existing
* commands of the same name. This should be called for the name of the command
* and each alias of the command.
*
* @param name name or alias of the command.
* @param command the command.
* @param helpTopic the help topic for the command or command alias.
*/
private static void forceCommand(String name, DenizenCommand command, HelpTopic helpTopic) {
// Override any existing non-DenizenCommand commands, but save them just in case
// TODO: use fallback prefixes for overridden commands instead?
if (knownCommands.containsKey(name)) {
overriddenCommands.put(name, knownCommands.get(name));
knownCommands.remove(name);
if (helpTopics.containsKey(name)) {
overriddenHelpTopics.put(name, helpTopics.get(name));
helpTopics.remove(name);
}
}
knownCommands.put(name, command);
helpTopics.put(helpTopic.getName(), helpTopic);
denizenCommands.put(name, command);
}
private static class IsCommandTopicPredicate implements Predicate<HelpTopic> {
public boolean test(HelpTopic topic) {
return apply(topic);
}
public boolean apply(HelpTopic topic) {
return topic.getName().charAt(0) == '/';
}
}
}