ModCommandManager.java 9.9 KB

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