Commander
Ever wanted to make an alias for those really long commands you have to type out constantly? Want to give players a simple one word command to warp somewhere? Want to create advanced scripts that run when you type a command? Want to clean up the server chat a bit?
Commander can do all that for you!
Commander is a find-replace plugin for commands and chat. It uses regular expressions to search player commands, player chat, or even console commands and replaces any matches with specified replacements! It even supports back references!
Commander is also a scripting language (Coming Soon!) which allows a single command to fire off a set of commands, with if statements and while loops and function calls! Oh my!
How it works
Commander examines player commands and server commands before proper processing of the commands even begins. It will use a list of regular expressions provided in the configuration folder and attempt to match the regex to the whole command. If it matches, it will replace the command with the specified replacement, be it a single command or a script!
For chat, it will attempt to find the regex in the chat somewhere, and replace the matched words with the specified replacement. Commander will even check if the word it found is in all caps, and, if it is, make the replacement in all caps as well! It also supports Command Words, which will fire off a command or script when the regex matches a word in the chat!
A Note about Permissions
Commander does not use permissions when matching, and there are no plans to make it use permissions. Commander simply finds and replaces the command regardless of permission status. There are also no permissions to bypass replacement - it will replace for all players regardless of permission status. If you wish to deny access to a command, you must deny access to the replacement. Note also: Players will not see the replacement command, they will only know what they entered worked or did not work.
Commander, however, does have support for Bukkit's built-in permissions in script (Coming Soon!). If you want to deny your players access to a command which fires off a script, you can put an if statement that checks if the current player has the proper permission!
Example Configuration
When you start up the plugin for the first time, Commander will place 3 text files in its data folder along with the config.yml. There is one file for each replacement context: player commands, player chat, and console commands. The following is the default player command file:
/cmode/ ==> gamemode $p 1 /smode/ ==> gamemode $p 0 /promote (.*)/ ==> pex promote $1 /demote (.*)/ ==> pex demote $1
The format is as follows: /find regex/ ==> replacement
The find regex is denoted by forward slashes (/). The replacement comes after the double equals arrow (==>).
Java regular expressions are fully supported (minus the escaping the backslash malarkey) and a guide to java regexes can be found here.
In the replacement string, the dollar sign ($) signifies a back reference to a capture group in the regex. Special back references can also be used relating to the player issuing them. The list of back references is as follows:
- $0 - $9 = back reference to a capture group in the regex (following java's model)
- $p = player name (not display name, but normal name)
- ....more to come....
Version 2.0 BETA
Version 2.0 is the advanced scripting overhaul. It is currently in alpha and may be unstable. However, while developing the scripting, I made sure all unit tests pass every time I change something, so there is the distinct possibility that all will work perfectly fine for your needs!
A comprehensive scripting reference guide can be found in the Pages tab!
Version 2.0 also adds an API for those who wish to use Commander's scripting language in their own plugin!
Version 1.2
(Yes, I realize now that I skipped version 1.1, because I thought zathrus's update was 1.1, when it was 1.0.1) Version 1.2 adds scripting!! Yay! To script, do this:
/regex/ =={ commands }
Version 1.2 also adds a helpful Reference.txt that gets copied to your data folder. There, it will explain in detail all the new changes that have taken place!
Known Bugs
- Command words (regexes matching against the chat which execute commands) run the commands before the chat message is broadcast, instead of afterward. The commands are still run in response to what you say in chat, it just doesn't seem like it...
- The [cutoff] parameter does not work properly due to the way it executes the command given to it. Due to this, cutoff will only work properly if the replacement word or phrase is the first or only thing said in the chat.+
- When parsing a script, the plugin will not detect uneven braces when there are too many open braces. This leads to commands after the orphaned open bracket not executing, as well as causing far more than just that script to be parsed as a script.+
- Backslashes, which are supposed to escape special characters, in fact remove the character they are supposed to escape.+
+ This has been fixed in the advancedScripting branch of development.
Planned Features
- More special replacement back references
- Advanced Scripting (in progress)
- Player persistent variables (session only). (for Version 2.0)
@trkah
It is in the correct file, right? Make sure to check if there are errors and how many replacements loaded in the console at startup.
@BlocklyCrafter
Those are called "regular expressions" or "regex" for short. That one captures one or more alphanumeric characters, then a space, then one or more digits, then possibly a space, then possibly one or more digits.
Go google "Regular expressions": I'm sure there's lots of resources that will explain much better than I care to right now.
why doesnt this work
/red/ ==> pb red /shop/ ==> pb shop /blue/ ==> pb blue /join/ ==> pb join /spec/ ==> pb spec /stats/ ==> pb stats thank you!
@tustin2121
Could you explain a little more about the "([a-zA-Z0-9]+) (\d+) ?(\d+)?" things? I'm still very bad at this, and I want to keep on doing this, but I can't when I don't know how to do it.. Could you explain more please? :)
Not really sure how this works.
I'm trying to replace /warp shop to just /shop a bit confused.
@tustin2121
Hey again, I worked out the reason for high timings, i have a voting plugin, that does a external database check, since removing that command my timing reports all show 0ms :D thanks again for your work on this project.
@Skyfalin
Yes, that would go in the playercmd.txt.
...I'm pretty sure all this is covered in the above description... and if not there, then certainly somewhere under the Pages tab....
@tustin2121
Oh thank you very much that sounds about right I will try it now. Also, because I am very challenged, would I put that in the playercmds folder?
@Skyfalin
I'm not sure if I'm just not understanding your question, but what you are saying is one of the major features of Commander. To make an alias to another command, simply enter it as a replacement:
or if this command (which I am not familiar with) has arguments:
Now all commands of /killstreak will become /kills. You can read up on the the various things Commander does under the Pages tab above.
@tustin2121
Hello, I have recently viewed your plugin and find it a great tool for creating custom commands. I do however have a question for you. I have nearly no knowledge of java, and was wondering if this plugin could..in a sense...'point'...a command to another command. I mean if I wanted to create a script that made it so when players do /killstreak, the server makes it so that they are actually just doing /kills through a different command, could I? Also, if so, could you send me that script?
@tustin2121
Thanks for the fast response, I believe the number tends to rise when other plugins are active and running many commands. I can see your point regarding the data source, i will remove these commands for the next test. I never use the reload command and our type of server is a hour long PvP game which resets with a server reboot. I will send you a full timing report so you can see other plugins activity. I'm glad to hear you build with optimization in mind. I will pm you my config and timings later when I'm at a pc, thanks again.
@LihPeu
Hm... interesting. Has the timing on Commander's processes always been this long, or has it been with a recent MC version update? Are you running on a fresh no-reload server (since /reload carries a lot of memory junk with it)?
Also, what's the average time (say over 5 or 10 runs) on PlayerCommandPreprocessEvent when the command is NOT a replacement, versus the same event when the command IS a replacement? Commander directly calls the action processing methods from a PlayerCommandPreprocessEvent (unless Bukkit does something I don't know about it and puts it in a queue) so command processing might be making it into that timing number.
Also consider that /news, last I checked, reads a file from the disk every time it runs, and disk access is the slowest basic process a computer does, aside from network access. Try repeating the above averages tests with a simple command like /time or something. If things have been getting gradually slower over time and this isn't connected to any Minecraft updates, then your server's disk access (and by extension running /news) might be getting slower due to normal fragmentation and size growth of the MC world data.
Granted, that alone is unlikely to cause things like a 10 second worst-case command run times; see also memory usage (number of players, number of chunks loaded, etc) and processes running (when I allowed TNT on my server one day, it was taken down easily by a good 1000 TNT blocks all attempting to explode at once. :P).
When I code, I usually try to keep things as optimized as possible on the first run through (people who say don't optimize when coding are pussies >:) ). I'm not saying I'm perfect, but I doubt something I'm doing, especially when you're not using the more advanced features like the scripting language, is causing a 10 second worst-case run time. I am interested in any test results you find though, so feel free to keep me posted. :)
Hey tustin2121,
First of all, thanks for your work on this project, i have been using it for a long time. I dont really make use of its great features, and lately i been noticing the huge latency in my timings reports. I can send you my config and timings reports if your interested. The example below is not great, but its high average and i have seen reports where its over 10s.
Commander v1.2.3
PlayerCommandPreprocessEvent Time: 2730208434 Count: 127 Avg: 21497704
ServerCommandEvent Time: 192205 Count: 2 Avg: 96102
Total time 2730400639 (2s)
The report above has only 15 lines in my playercmd.txt and the rest of my txt files are empty. The majority are simple things like the following:
/credits/ ==> news credits
/host/ ==> news host
/chat/ ==> news chat
/play/ ==> news play
/forum(.*)/ ==> news forums
/vote/ ==> v4c vote
<<reply 1138556="">>
Thank you so much ! :DD You, my friend is my god! It's like having my own plugin now :D Own commands, and own messages :3 Me loves you. :D
@BlocklyCrafter
....I did. Did you read any of what I said?
Regardless, here's in full then....
Edit: I walked through the regex in English below each.
<<reply 1138283="">>
So can you somehow fix my script?
I kinda didn't understand "(\d+) (\d+) ?(\d+)?/" ._.
@BlocklyCrafter
Ah, well, regular expressions are powerful, but they aren't magical. Let me explain.
A capture group (which is what Commander is complaining there is no number 2 of) is a group of parenthesis (()) which captures a select portion of the input to be used as back references ($1, etc) in the output, counting up from 1. What you have is this:
meaning "match the phrase "give ", note space at end, then take anything that's left and put it into capture group 1".
This means in your example command, it matches "give " and then matches "BlockyMiner 35 64 5" and puts that into capture group 1. There's now no capture groups 2, 3, or 4 to pull from, which is what gives the error. (Aside: capture group 0 holds the entire matched command. So putting $0 in your output will print the whole command that you captured)
For your example, you'll want something like the following:
Meaning "match the phrase "give ", space at the end, then one or more characters made of letters (lower and uppercase) or numbers for capture group 1, then a space, then a one or more numbers for capture group 2, then a space, then one or more numbers for capture group 3, then possibly a space, then possibly one or more numbers for capture group 4."
Those possibles at the end are from the question marks, which make it so you dont have to put in a 3rd number (which you won't most time, given the command) and the expression will still match. It won't complain about a missing 4th group because it's still defined in the expression, just empty, and it will be just empty in the output.
You'll want to add one to all your back references in your commands: "give $1 $2 $3 $4".
Commander uses standard regular expressions, so you can learn more at any online resource. I use www.regular-expressions.info. Another nifty tool you will find useful when making these is regexpal.com, where you can test your regexes against your data and instantly see the results (turn case insensitive on, as all of Commander's regexes are compiled with that flag on by default). :)
<<reply 1136673="">>
Thank you so much. I have a question... When running /give BlocklyMiner 35 64 5 it gives me error in console "[Commander] No group 2" and then some java stuff. This is my script:
/give (.*)/ =={
give $0 $1 $2 $3
enjin broadcast &b$p&9 gave &b$0 $1 &9of &b$2&9:&$3&9.
}
@tustin2121
Thanks so much for your help! It looks like rTriggers is probably a dead plugin now that 1.4.6 is out. I'm scrambling to switch over to Commander. Right now the only things stopping me are the # script problem and no support for OnJoin, OnDeath, etc overrides for default messages. I may be able to find another plugin for those.
@jaggy80
You can't, as the code stands right now. The ampersand (#) is used for comments, and therefore get stripped out unconditionally as the first step of processing a code line. I will have to fix it so that the ampersand can be escaped with a backslash and survive if put inside quotes and stuff.
I'm not sure if there's a work around at the moment. Unless minecraft has a unicode character syntax or something... in which case the number would be 0026. If not, I can probably add that too.
@BlocklyCrafter
Use a script:
See the Pages tab. There's a (mostly) full manual of how to use all the current features of both versions of Commander. The latest version has a much more advanced scripting feature set, but the basic scripting syntax is the same.
Works: /amsg (.*)/ ==> sudo irc raw msg #AdminChat :.a ($p) $1
Works: /amsg (.*)/ ==> sudo irc raw msg ircmembername :.a ($p) $1
Fails: /amsg (.*)/ =={
sudo irc raw msg #AdminChat :.a ($p) $1
}