[Lib] Change no permission message without packet interception

Discussion in 'Resources' started by werter318, Jun 11, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    werter318

    Hello,

    This little method I made changes the no permission message ("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.") without using any packet interception libraries like ProtocolLib or PacketLib. Currently you need to have CraftBukkit as a dependency, but if someone wants this to work without the CraftBukkit dependency I will make a little method for that as well!

    I'm not sure if this has been done, but I doubt it.

    Code:

    Code:java
    1. public void changeNoPermissionMessage(final String message) {
    2. new BukkitRunnable() {
    3.  
    4. @Override
    5. public void run() {
    6. CraftServer craftServer = ((CraftServer) getServer());
    7.  
    8. SimpleCommandMap commandMap = null;
    9. Map<String, Command> knownCommands = null;
    10.  
    11. try {
    12. Field commandMapField = craftServer.getClass().getDeclaredField("commandMap");
    13. commandMapField.setAccessible(true);
    14. commandMap = (SimpleCommandMap) commandMapField.get(craftServer);
    15.  
    16. Field knownCommandsField = commandMap.getClass().getDeclaredField("knownCommands");
    17. knownCommandsField.setAccessible(true);
    18. knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap);
    19. e.printStackTrace();
    20. }
    21.  
    22. Field permissionMessageField = null;
    23.  
    24. try {
    25. permissionMessageField = Command.class.getDeclaredField("permissionMessage");
    26. permissionMessageField.setAccessible(true);
    27. e.printStackTrace();
    28. }
    29.  
    30. for (String alias : knownCommands.keySet()) {
    31. Command command = knownCommands.get(alias);
    32.  
    33. try {
    34. permissionMessageField.set(command, message);
    35. e.printStackTrace();
    36. }
    37. }
    38. }
    39. }.runTaskLater(this, 10L * 20L);
    40. }


    Example Usage in onEnable():

    Code:java
    1. changeNoPermissionMessage(ChatColor.RED + "Sorry, no permission!");


    P.S: Some servers don't want players to see what commands they have so you can fake the command not found message with this aswell!
     
  2. Offline

    BungeeTheCookie

    werter318
    This is spectacular! Can you add a changeCommandNotFound() message as well? I don't know what the declared field for that is :p
     
  3. Offline

    werter318

    BungeeTheCookie Thank you!

    Sadly you can't change that message (Magic) ->

    [​IMG]
     
  4. Offline

    BungeeTheCookie

    Any way to clear a method inside a class and then do all of that?
     
  5. Offline

    xTrollxDudex

    BungeeTheCookie
    Well, if you could get into the stack frame of the method call, then you could... Otherwise, it would need to be protocol lib :/
     
  6. Offline

    BungeeTheCookie

    Comphenix
     
  7. Offline

    Comphenix

    You could proxy the CraftServer singleton, by replacing the existing instance in the Bukkit class with reflection. Then you just copy the implementation of dispatchCommand() into your proxy, and make the necessary adjustments there.

    But you have to be really careful, and ensure you clean up after yourself after your plugin has been disabled. It's also a bit of a step back in comparison to intercepting packets, as you now run the risk of conflicting with other plugins.

    Why not use TinyProtocol instead? It shouldn't take too much work to convert this example. Or, you could use
    PlayerCommandPreprocessEvent and intercept the chat even before it ever gets processed by Bukkit. Then you'd just check if a given command exists using CraftServer.getCommandMap().
     
    Garris0n likes this.
  8. Offline

    Dablakbandit

  9. Offline

    werter318

    Dablakbandit

    Yeah, I thought about that as well, that's a nice way of doing it.
     
  10. Offline

    Cirno

    I firmly believe it's possible; it is, however, a very knarly and most likely next to impossible hack. In Java, the strings are normally cached so that they can be called later on a lot more quickly and is also a reason why we don't call "new String()" every time we want to create a String. Digging with Google, I found this which is the String cache coded with C++(?). If someone was smart enough to figure out how to basically hack the cache, it's possible. I highly doubt it since there seems to be no equivalent of Java's reflection for C++. Maybe if someone memory edited the process, then we can get somewhere. All I know is that this is probably way out of everybody's reach and is probably not worth the effort when you can just use a Listener (like Dablakbandit showed) and just cancel the event.
     
  11. Offline

    matzefratze123

    It's actually pretty simple to change a string in the string-pool. I figured this out, by changing the "value" field inside the String class. It is final but still editable when setting the field's accessibility to true. Here is a method to change the unknown-command message:

    Code:java
    1. public class StringPoolHack {
    2.  
    3. public static void changeUnknownCommandMessage(String newMessage) {
    4. final String defaultUnknownCmdMsg = "Unknown command. Type \"/help\" for help.";
    5.  
    6. try {
    7. //Get the value field, since String is not immutable
    8. Field valueField = String.class.getDeclaredField("value");
    9. boolean accessible = valueField.isAccessible();
    10.  
    11. valueField.setAccessible(true);
    12. valueField.set(defaultUnknownCmdMsg, newMessage.toCharArray());
    13.  
    14. valueField.setAccessible(accessible);
    15. } catch (Exception e) {
    16. throw new RuntimeException(e);
    17. }
    18. }
    19.  
    20. }


    But note that whenever you are now using the default message somewhere else, you get the custom message you gave the message above. I tested this with my local server and it seems to work properly.
     
  12. Offline

    werter318

    matzefratze123 Well, you didn't figure that out yourself, but okay. I actually tried this before you posted this but it didn't work.
     
  13. Offline

    ChipDev

    Code:java
    1. getServer().getPluginCommand("Example").setPermissionMessage(ChatColor.RED + "Doge says wow. you no perms.");
    2.  

    Bam.
    1 line.
     
  14. Offline

    werter318

    ChipDev Yeah... this won't handle other plugins' commands.
     
  15. Offline

    ChipDev

    What..? It won't?
    I put this in onEnable and it works perfectly, even to change other permissions. It overrides the config.yml.
     
  16. Offline

    werter318

    ChipDev Yeah, what I meant to say was that it doesn't do ALL the commands, you have to do that for every command, my version does all the registered commands.
     
  17. Offline

    ChipDev

    Oh. :p
     
Thread Status:
Not open for further replies.

Share This Page