Information regarding calling player.performCommand(..)

Discussion in 'Resources' started by blablubbabc, Oct 14, 2013.

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

    blablubbabc

    Hey,

    this message goes to everybody who is in some way calling player.performCommand(..) in his plugin (examples are command signs, button commands, region enter/leave triggered commands, etc.).

    I recently found out that the PlayerCommandPreprocessEvent is only called, if the command was triggered directly by a player's chat packet.

    As I always thought that this event would generally, automatically be called when a command is about to get executed and as I thought listening for it and canceling it would be the easiest way to stop players from executing commands in certain situations,
    I created a ticket for bukkit, asking for also throwing an event, when a command gets executed via player.performCommand(..)

    However, it was declined with the hint that those plugins, which call player.performCommand(..), should call a PlayerCommandPreprocessEvent themselve in order to act appropriately.

    I personally would say that this event should automatically be called by craftbukkit when player.performCommand(..) is called, so nobody has to bother with this, but it doesn't seem that I can change much on this decision, sadly..

    So here I am, asking everyone to call a PlayerCommandPreprocessEvent before you actually call player.performCommand(..)

    That way other plugins can easily react or cancle commands executed this way, and not only the chat triggered ones. This helps interaction between different plugins a lot.

    Here is an example how this could look like in your plugin:

    Code:java
    1. /* .. your plugin .. */
    2.  
    3. PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(player, command);
    4. Bukkit.getPluginManager().callEvent(event);
    5.  
    6. // only perform the command, if the event wasn't cancelled by an other plugin:
    7. if (!event.isCancelled()) {
    8. player.performCommand(event.getMessage());
    9. }
    10.  
    11. /* .. your plugin .. */



    In regards
     
    DarkBladee12, _DSH105_ and Skyost like this.
  2. Offline

    MrSparkzz

    blablubbabc
    This is all alright, but when people do player.performCommand(); It will send the command to the plugin it's accessing and that should be the only use for that. So this thread serves no purpose.

    If you're going to override a command you'd use the PlayerCommandPrePreprocessEvent, if you're going to make a command without using standard methods, you'd use AsyncPlayerChatEvent. Though this is not recommended, it's useful.

    To be completely honest, I don't see the reason behind this thread. If you send a command through player.performCommand(); It will access the command list, check the plugin that has that command, then go through the methods to make it work. If they don't meet a certain requirement within the plugin you're sending the command to, then (if the plugin is coded properly) they wont be able to use the command.
     
  3. Offline

    blablubbabc

    That's right. But it does not provide any possibility for other plugins to react to this, like it would be the case if the player directly typed in the command in chat.

    The PlayerCommandPreprocessEvent is meant for plugins to intercept command execution and either cancle it (prevent the command execution from happening) or "override" / modify it or somehow else react to it (for example command logging).

    "If they don't meet a certain requirement within the plugin you're sending the command to, then (if the plugin is coded properly) they wont be able to use the command."

    It gets difficulty when there are multiple plugins which want work together nicely: an other plugin might want to decide that the requirements for executing this command are not met. An other plugin might want to add additionally requirements, dynamically dependent on a players current state / situation.

    And you don't want to build in "support" and "specialized" code for each individual plugin your plugin might be run together. Instead, to support all plugins which your plugin is potentially being run together with, you would use the existing event system of bukkit to throw some sort of custom event to allow other plugins to react to what your plugin does. And this is exactly what I suggest everyone to do here: call an event (in this case an already exisiting one, which is meant for exactly this case) to give other plugins the chance to react to what your plugin does.


    Many plugins use player.performCommand(..) as an alternative to let a player execute a command, just like the player would if he typed in the command in his chat manually. However, it is not really an alternative, because instead of when the player types in the command, no PlayerCommandPreprocessEvent is called. So you should call this manually yourself, when you want to "simulate" the player to perform a command.

    This thread is meant to let everyone know about this. Personally I wasn't aware myself for a very long time, that this event is not being called automatically when a command is about to get executed, even though it states so (it's isn't called PlayerCommandPreprocessEvent" for no reason).
     
    Ultimate_n00b, Skyost and Comphenix like this.
  4. Offline

    MrSparkzz

    blablubbabc
    I don't want you to be one of those people that when I post again will get angry and start treating me like an idiot, so I'll rephrase my response:

    The only use I see for these things are
    1. .performCommand() => using /h (command sending request) instead of /help (standard format). Maybe even making something like this: /h sends command /help 2. Basically this method is just used to simplify things.
    2. PlayerCommandPreprocessEvent => Used to cancel a command before it's used or Make the command do something other than what it originally should (cancelling, then using your own code).
    3. AsyncPlayerChatEvent (For Commands) => Used to create custom commands defined in a configuration file (not recommended).
    If you use them in any other form, then you're bound to have problems.
     
  5. Offline

    blablubbabc

    That won't be a problem for me :)
    I will try give response to your response as good as I can (I am not nativly speaking english, so it sometimes gets difficulty to clearly express myself, but I give my best)

    to 1.) -> I don't completly understand you there. But I think you are talking about using player.performCommand(..) to create command "aliases". However, I wouldn't use player.performCommand(..) for that, but instead listen to the PlayerCommandPreprocessEvent, check if event.getMessage().equalsIgnoreCase("h") and then call event.setMessage("help").
    (Or, if you can convince the author of the command "/help", add this aliase directly in his plugin.yml)

    to 2.) -> That's exactly what I often see myself using it for and what I see as one of the reasons for this event. However, if a plugin calls player.performCommand(..) you can't cancle this command from an other plugin that easily (by listening and cancling this PlayerCommandPreprocessEvent), because none is called. That's the reason why I wrote this thread, to ask everybody to call a PlayerCommandPreprocessEvent if you call player.performCommand(..). That way we both can keep using this event in our plugins to cancle command execution easily.

    to 3.) -> I don't think that an AsyncPlayerChatEvent is even called, when a player types in a command (starting with '/') .. if you take a look the source code of Craftbukkit you can find this: https://github.com/Bukkit/CraftBukk...t/minecraft/server/PlayerConnection.java#L877 -> there it is checked if the chat message is a command and then it calls the PlayerCommandPreProcessEvent and after that is does the same what player.performCommand(..) does: checking the command map for the executing plugin and letting it execute.

    The AsyncPlayerChatEvent however is created 4 lines below in the else-block (which is never reached, if the message was a command)
     
  6. Offline

    MrSparkzz

    blablubbabc
    1. When creating command aliases, you wouldn't use PlayerCommandPreprocessEvent, unless (like in this case) the command alias is already being used. If you were to use PlayerCommandPreprocessEvent to create a command alias, if I'm not mistaken, wouldn't do anything or would do the same thing as not using an event for it.For this one, you're correct.
    2. When cancelling commands, if a dev uses .performCommand(); Then it'd still be calling the original command. So another dev could still easily cancel the command.
    3. For this one, you're correct.
     
  7. Offline

    blablubbabc

    MrSparkzz

    If I want to create an aliase for my own plugin, I would use the command section in the plugin.yml
    But if I should want to create a command alias for an other plugin's command -> of course I would use this event, as it provides me everything I need for that: event.getMessage() returns the command which will be executed after the event and with event.setMessage(..) you can modify it, to run a different command instead.

    Edit: it somehow removed my answer here :(

    Here you can see that craftbukkit does indeed use the message from the PlayerCommandPreprocessEvent to determine which command to execute.

    Because player.performCommand(..) directly executes the command (without a PlayerCommandPreprocessEvent between), only the plugin which command gets executed can react to it (if he doesn't provide events or api for other plugins). Instead, when you would call a PlayerCommandPreprocessEvent before you call player.perfromCommand(..) other plugins would be able to influence the outcome of this call easily and uniformly (without specialized api or events on the executed command's end)
     
  8. Offline

    MrSparkzz

    Ah, I see, thank you for divulging deeper into your reasoning without getting upset.
     
  9. Offline

    Dread9Nought

    I'm not quite sure if this should surprise me; it's always something I've wondered about when using it but have never had a reason to look; or to be frank; care; that is since it (currently)has caused no problems.

    However, as the OP said - I would much rather there to be a boolean of some-sort to allow overriding of this.

    For example
    performCommand(String command)
    performCommand(String command, boolean silent)

    This would allow ALL-Existing plugins to continue working and give plugin developers the freedom to not be forced to do anything, merely give them (literally) a yes/no choice as to whether they want this to override the CommandPreProcessEvent..

    I guess this is something that needs to be touched upon.
     
  10. Offline

    blablubbabc

    Dread9Nought
    The usual way to force a command's code to be executed would be to directly execute that code. Or listen with a higher event priority than the plugins which cancle the PlayerCommandPreprocessEvent (if multiple plugins are invloved, which might want to cancle/not cancle a command in certain situations -> if you want to force a command to be executed which got triggered by another plugin (ignoring for now why you might even want that)).
    Coordinating plugins is exactly why there are different event priorities in bukkit's event system, so you should use it as often as possible and not simple force-exec your code/a command, because by that you cut off the possibility and opportunities for plugins to easily extend or modify or somehow else react to the processes of your plugin.

    Bukkit is no longer only about to react to certain events and actions of the minecraft server and world ("block this" / "add that"), but also about running multiple plugins together which add to each other and expand the minecraft experience even more by providing new possibilities together (one plugin offers economy handling, other plugins use it and create a variety of possibilities around it, or, an other example, some plugins add commands which each do different things, and an other plugin logs it when users execute those commands, complelty independently, without having to know which exact plugins are running and which concrete commands are being executed).
    And in order for everything to work nicly together, events like this one are needed / help a lot.

    As the ticket which requested to automatically call a PlayerCommandPreprocessEvent was denied anyways, each plugin author has the choice to call an PlayerCommandPreprocessEvent, or not.

    However, as most plugins use player.performCommand(..) as direct alternative to the player typing in that command (command signs, command buttons, etc. -> in general: automatically triggered commands / "just like if the player would have automatically typed in that command in that situation"), there is no good reason for them to not call this event.
    The situations where you might want to force-exec a command are much less and uncommon, compared to how I think player.perfromCommand(..) is currently used in plugins.
     
  11. Offline

    Dread9Nought


    Precisely, I couldn't agree more. Calling it yourself each time you want to use a method rather than bukkit putting it inside the method itself is simply beyond me, I thought we strived for ease-of-use?
     
  12. Offline

    DarkBladee12

    blablubbabc Do you know if "Bukkit.dispatchCommand(sender, commandLine)" doesn't fire an event too? Because I'd like to replace "performCommand(...)" with this in the new version of my SimpleAlias plugin, if not I can also add the event call with ease. But as I'm understanding it right so far there's no way to get commands executed by another plugin? (I'd really like to make aliases also usable in other plugins)
     
  13. Offline

    blablubbabc

    DarkBladee12
    player.performCommand(..) is actually calling server.dispatchCommand(..) internal, so, no, no event being called there either.. :(

    So, yes, please call an PlayerCommandPreprocess (if your command is going to be executed by a player. If it is going to be called by the ConsoleCommandSender you would want to call a ServerCommandEvent instead), and create your aliases for other plugin's commands by listening to the PlayerCommandPreprocessEvent on a low priority and change the command via event.setMessage(..) there (still giving other plugins the possibility to react to that changed command on a higher priority than you).
     
Thread Status:
Not open for further replies.

Share This Page