ModCommandManager.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. package me.km.permissions;
  2. import com.google.common.collect.Maps;
  3. import com.mojang.brigadier.builder.ArgumentBuilder;
  4. import com.mojang.brigadier.builder.RequiredArgumentBuilder;
  5. import com.mojang.brigadier.tree.CommandNode;
  6. import com.mojang.brigadier.tree.RootCommandNode;
  7. import java.util.ArrayList;
  8. import java.util.HashMap;
  9. import java.util.HashSet;
  10. import java.util.Map;
  11. import me.hammerle.snuviscript.code.ISnuviScheduler;
  12. import me.km.events.CommandEvent;
  13. import me.km.snuviscript.ScriptEvents;
  14. import me.km.snuviscript.Scripts;
  15. import net.minecraft.command.CommandSource;
  16. import net.minecraft.command.Commands;
  17. import net.minecraft.command.ICommandSource;
  18. import net.minecraft.command.ISuggestionProvider;
  19. import net.minecraft.command.arguments.SuggestionProviders;
  20. import net.minecraft.entity.Entity;
  21. import net.minecraft.entity.player.PlayerEntity;
  22. import net.minecraft.entity.player.ServerPlayerEntity;
  23. import net.minecraft.network.play.server.SCommandListPacket;
  24. public class ModCommandManager extends Commands {
  25. private final HashSet<String> otherCommands = new HashSet<>();
  26. private final HashMap<String, Command> commands = new HashMap<>();
  27. private final Permissions perms;
  28. private final ScriptEvents events;
  29. private final Scripts scripts;
  30. private final ArrayList<CommandNode<?>> customNodes = new ArrayList<>();
  31. private final HashSet<String> ignoredCommands = new HashSet<>();
  32. public ModCommandManager(Permissions perms, ScriptEvents events, Scripts scripts,
  33. ISnuviScheduler scheduler) {
  34. super(EnvironmentType.DEDICATED);
  35. getDispatcher().getRoot().getChildren().forEach(c -> {
  36. otherCommands.add(c.getName());
  37. });
  38. scheduler.scheduleTask("ModCommandManager", () -> {
  39. getDispatcher().getRoot().getChildren().forEach(c -> {
  40. if(otherCommands.add(c.getName())) {
  41. perms.addOtherGroupPermission(c.getName());
  42. }
  43. });
  44. });
  45. this.perms = perms;
  46. this.events = events;
  47. this.scripts = scripts;
  48. // forge command which fails ...
  49. ignoredCommands.add("config");
  50. }
  51. public void clearCustomNodes() {
  52. customNodes.clear();
  53. }
  54. public void addIgnoredCommands(String command) {
  55. ignoredCommands.add(command);
  56. }
  57. public void clearIgnoredCommands() {
  58. ignoredCommands.clear();
  59. // forge command which fails ...
  60. ignoredCommands.add("config");
  61. }
  62. public void addCustomNode(CommandNode<?> node) {
  63. customNodes.add(node);
  64. }
  65. public void registerCommand(Command command) {
  66. commands.put(command.getName(), command);
  67. for(String alias : command.getAliases()) {
  68. commands.put(alias, command);
  69. }
  70. }
  71. private String getCommandName(String rawCommand) {
  72. if(rawCommand.isEmpty()) {
  73. return "";
  74. }
  75. int index = rawCommand.indexOf(' ');
  76. return rawCommand.substring(rawCommand.charAt(0) == '/' ? 1 : 0,
  77. index == -1 ? rawCommand.length() : index);
  78. }
  79. private static String[] getArguments(String rawCommand) {
  80. int old = rawCommand.indexOf(' ') + 1;
  81. if(old == 0) {
  82. return new String[0];
  83. }
  84. int pos = old;
  85. ArrayList<String> list = new ArrayList<>();
  86. while(pos < rawCommand.length()) {
  87. char c = rawCommand.charAt(pos);
  88. switch(c) {
  89. case ' ':
  90. if(pos - old > 0) {
  91. list.add(rawCommand.substring(old, pos));
  92. }
  93. old = pos + 1;
  94. break;
  95. case '"':
  96. if(pos - old > 0) {
  97. list.add(rawCommand.substring(old, pos));
  98. }
  99. old = pos + 1;
  100. pos = old;
  101. while(pos < rawCommand.length() && rawCommand.charAt(pos) != '"') {
  102. pos++;
  103. }
  104. list.add(rawCommand.substring(old, pos));
  105. old = pos + 1;
  106. break;
  107. }
  108. pos++;
  109. }
  110. if(pos - old > 0) {
  111. list.add(rawCommand.substring(old, pos));
  112. }
  113. return list.toArray(new String[list.size()]);
  114. }
  115. private ICommandSource getSource(CommandSource cs) {
  116. if(cs.getEntity() != null) {
  117. return cs.getEntity();
  118. }
  119. return cs.getServer();
  120. }
  121. private String lowerRawCommand(String raw) {
  122. int index = raw.indexOf(" ");
  123. if(index == -1) {
  124. return raw.toLowerCase();
  125. }
  126. return raw.substring(0, index).toLowerCase() + raw.substring(index);
  127. }
  128. @Override
  129. public int performCommand(CommandSource cs, String rawCommand) {
  130. rawCommand = lowerRawCommand(rawCommand);
  131. String commandName = getCommandName(rawCommand);
  132. Command command = commands.get(commandName);
  133. if(command != null) {
  134. if(perms.has(cs, command.getName())) {
  135. command.execute(getSource(cs), getArguments(rawCommand));
  136. return 1;
  137. }
  138. events.onMissingPermission(getSource(cs), command.getName());
  139. return 0;
  140. }
  141. if(scripts.isRegisteredScriptCommand(commandName)) {
  142. Entity ent = cs.getEntity();
  143. if(ent != null && ent instanceof PlayerEntity) {
  144. events.onCustomCommand((PlayerEntity) ent, commandName, getArguments(rawCommand));
  145. return 1;
  146. }
  147. events.onCustomCommand(null, commandName, getArguments(rawCommand));
  148. return 0;
  149. }
  150. if(otherCommands.contains(commandName)) {
  151. if(perms.has(cs, commandName)) {
  152. Entity ent = cs.getEntity();
  153. if(ent != null && ent instanceof PlayerEntity) {
  154. CommandEvent e = new CommandEvent((PlayerEntity) ent, commandName);
  155. events.onCommand(e);
  156. if(e.isCanceled()) {
  157. return 0;
  158. }
  159. }
  160. return super.performCommand(cs, rawCommand);
  161. }
  162. events.onMissingPermission(getSource(cs), commandName);
  163. return 0;
  164. }
  165. events.onMissingCommand(getSource(cs), commandName);
  166. return 0;
  167. }
  168. @SuppressWarnings({"unchecked", "rawtypes"})
  169. @Override
  170. public void sendCommands(ServerPlayerEntity player) {
  171. Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> map = Maps.newHashMap();
  172. RootCommandNode<ISuggestionProvider> rootNode = new RootCommandNode<>();
  173. map.put(getDispatcher().getRoot(), rootNode);
  174. CommandSource cs = player.createCommandSourceStack();
  175. commandSourceNodesToSuggestionNodes(true, getDispatcher().getRoot(), rootNode, cs, map);
  176. for(CommandNode node : customNodes) {
  177. commandSourceNodesToSuggestionNodes(node, rootNode, cs, map);
  178. }
  179. player.connection.send(new SCommandListPacket(rootNode));
  180. }
  181. @SuppressWarnings({"unchecked", "rawtypes"})
  182. private void commandSourceNodesToSuggestionNodes(boolean first, CommandNode<CommandSource> node,
  183. CommandNode<ISuggestionProvider> suggestion, CommandSource source,
  184. Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> map) {
  185. for(CommandNode<CommandSource> childNode : node.getChildren()) {
  186. if(first && ignoredCommands.contains(childNode.getName())) {
  187. continue;
  188. }
  189. if((first && perms.has(source, childNode.getName())
  190. || (!first && childNode.canUse(source)))) {
  191. ArgumentBuilder<ISuggestionProvider, ?> arg =
  192. (ArgumentBuilder) childNode.createBuilder();
  193. arg.requires(a -> true);
  194. if(arg.getCommand() != null) {
  195. arg.executes(a -> 0);
  196. }
  197. if(arg instanceof RequiredArgumentBuilder) {
  198. RequiredArgumentBuilder<ISuggestionProvider, ?> required =
  199. (RequiredArgumentBuilder) arg;
  200. if(required.getSuggestionsProvider() != null) {
  201. required.suggests(
  202. SuggestionProviders.safelySwap(required.getSuggestionsProvider()));
  203. }
  204. }
  205. if(arg.getRedirect() != null) {
  206. arg.redirect(map.get(arg.getRedirect()));
  207. }
  208. CommandNode<ISuggestionProvider> commandNode = arg.build();
  209. map.put(childNode, commandNode);
  210. suggestion.addChild(commandNode);
  211. if(!childNode.getChildren().isEmpty()) {
  212. this.commandSourceNodesToSuggestionNodes(false, childNode, commandNode, source,
  213. map);
  214. }
  215. }
  216. }
  217. }
  218. @SuppressWarnings({"unchecked", "rawtypes"})
  219. private void commandSourceNodesToSuggestionNodes(CommandNode<CommandSource> node,
  220. CommandNode<ISuggestionProvider> parentNode, CommandSource cs,
  221. Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> map) {
  222. if(!node.canUse(cs)) {
  223. return;
  224. }
  225. ArgumentBuilder<ISuggestionProvider, ?> arg = (ArgumentBuilder) node.createBuilder();
  226. arg.requires(a -> true);
  227. if(arg.getCommand() != null) {
  228. arg.executes(a -> 0);
  229. }
  230. if(arg instanceof RequiredArgumentBuilder) {
  231. RequiredArgumentBuilder<ISuggestionProvider, ?> required =
  232. (RequiredArgumentBuilder) arg;
  233. if(required.getSuggestionsProvider() != null) {
  234. required.suggests(
  235. SuggestionProviders.safelySwap(required.getSuggestionsProvider()));
  236. }
  237. }
  238. if(arg.getRedirect() != null) {
  239. arg.redirect(map.get(arg.getRedirect()));
  240. }
  241. CommandNode<ISuggestionProvider> commandNode = arg.build();
  242. map.put(node, commandNode);
  243. parentNode.addChild(commandNode);
  244. for(CommandNode<CommandSource> childNode : node.getChildren()) {
  245. commandSourceNodesToSuggestionNodes(childNode, commandNode, cs, map);
  246. }
  247. }
  248. }