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)
@tustin2121
Hello, Thank you for help! It works perfectly with §! By the way, I had learnt PHP regex some time ago, and it seems to me that they are the same as Java's. Am I right?
@tmackb24
/w (.*)/ ==> warp $1
Go check out the various help files under the Pages tab.
@kbryantLA24
Well, yes, it is literally placing the name into the command, so there should't be any problem there. I'm interested in the fact that it sometimes works, despite my plugin always giving the same wrapped sender to the command...
@tustin2121
Yeah I wasn't sure, which is why I brought this to your attention. If your plugin was literally just placing that argument into anticheat's command, it should still register the partial name?
I am using essentials and I want to be able to use "/w <name>" instead of "/warp <name>". How or what do I need to put for the name of the warp in the config?
@kbryantLA24
I don't know why that makes a difference. Granted, I am not the creator of the anti-cheat plugin, so don't expect me to know. :/
However, the stack trace in this post is slightly different from the last post: the method being called is "hidePlayer" here, where as it is "showPlayer" in the last one...
@tustin2121
Thanks for the thorough response. I toyed around with it more and discovered something that may or may not be related.
When I use partial player names with the original command, it works. For example, if I want to spy on PlayerFooBar, I type "/anticheat spy player" and it works.
If I use the Commander alias with the full name, it works: "/spy playerfoobar" However if I use the Commander alias with a partial name, it fails: "/spy player" Console spits out:
10:25:35 [SEVERE] [Commander] An exception was caught during player command replacement processing! Command passed through. org.bukkit.command.CommandException: Unhandled exception executing command 'anticheat' in plugin AntiCheat v1.3.8-U2 at org.bukkit.command.PluginCommand.execute(PluginCommand.java:42) at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:168) at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:498) at org.digiplex.bukkitplugin.commander.scripting.ScriptLine.execute(ScriptLine.java:52) at org.digiplex.bukkitplugin.commander.replacement.ReplacementCommand.executeEffects(ReplacementCommand.java:40) at org.digiplex.bukkitplugin.commander.module.PlayerCommandModule.onPlayerCommandPreprocess(PlayerCommandModule.java:55) at sun.reflect.GeneratedMethodAccessor198.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:339) at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:477) at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:462) at net.minecraft.server.NetServerHandler.handleCommand(NetServerHandler.java:872) at net.minecraft.server.NetServerHandler.chat(NetServerHandler.java:826) at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:808) at net.minecraftserverhook.NetServerHandlerProxy.a(NetServerHandlerProxy.java:124) at net.minecraft.server.Packet3Chat.handle(Packet3Chat.java:44) at net.minecraft.server.NetworkManager.b(NetworkManager.java:282) at net.minecraft.server.NetServerHandler.d(NetServerHandler.java:109) at net.minecraft.server.ServerConnection.b(SourceFile:35) at net.minecraft.server.DedicatedServerConnection.b(SourceFile:30) at net.minecraft.server.MinecraftServer.q(MinecraftServer.java:577) at net.minecraft.server.DedicatedServer.q(DedicatedServer.java:213) at net.minecraft.server.MinecraftServer.p(MinecraftServer.java:473) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:405) at net.minecraft.server.ThreadServerApplication.run(SourceFile:539) Caused by: java.lang.ClassCastException: org.digiplex.bukkitplugin.commander.scripting.EchoControlPlayer cannot be cast to org.bukkit.craftbukkit.entity.CraftPlayer at org.bukkit.craftbukkit.entity.CraftPlayer.hidePlayer(CraftPlayer.java:614) at net.h31ix.anticheat.CommandHandler.handleSpy(CommandHandler.java:206) at net.h31ix.anticheat.CommandHandler.onCommand(CommandHandler.java:591) at org.bukkit.command.PluginCommand.execute(PluginCommand.java:40) ... 26 more
@xou816
Fast response because I get emailed about new comments. Ironically, I don't get emailed about edits to comments. :P
Did you try the color codes with the section symbol ( § )? I'll put in a ticket about implementing something with, idk, ampersand ( & ) or something, for easy use. Not sure when I'll have time to get to it, but it'll be on my list. :j
@kbryantLA24
Hm... Did I forget to release the update making those exceptions more player friendly? Or are you running an older version of the plugin? This is actually an exception thrown by the anti cheat plugin, caught and rethrown by Commander.
However, the exception is partially Commander's fault. As part of the echo control portion of Commander, Commander wraps the player object in an "EchoControlPlayer" object, which, when using the Bukkit API, does everything a normal player does and works perfectly.
BUT, CRAFTBUKKIT (of all things) blindly assumes that it is being passed a normal player from the craftbukkit implementation of the Bukkit API, and attempts to call a method on it that is not in the normal Bukkit API but only available to the craftbukkit implementation itself. Basically the developers of craftbukkit didn't take into account that they may be passed something that is not their own player object, but a wrapper around such, as I am passing them. I mean, I guess it makes some sense, maybe...
As to why it works the second time is beyond me. Maybe theres a bug in MY code where I'm not always giving the echo controlled player. I don't know.
I don't know how I would fix this without removing EchoControl. If the developer of the anti-cheat plugin added special handling for the echo controlled player, it would fix it, but I'm not vain enough to expect him to add ONE special case for MY plugin. In a general sense, the developers of Craftbukkit should add a check to ensure they're not blindly casting, but I don't know what they would do to get the real object beyond adding some superfluous method to the Bukkit API...
Sorry, I'm rambling. tl;dr: this is my fault in practice, but technically craftbukkit's fault with assumptions. I don't know how to fix it without compromising functionality. :/
Hey, so right now I have this:
/spy (.*)/ ==> anticheat spy $1
where the argument is a player name. I have to type "/spy <playername>" twice for this to work. The first type I type the command, it says "Unknown command" in-game, while the console throws this error:
02:57:23 [SEVERE] [Commander] An exception was caught during player command replacement processing! Command passed through. org.bukkit.command.CommandException: Unhandled exception executing command 'anticheat' in plugin AntiCheat v1.3.8-U2 at org.bukkit.command.PluginCommand.execute(PluginCommand.java:42) at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:168) at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:498) at org.digiplex.bukkitplugin.commander.scripting.ScriptLine.execute(ScriptLine.java:52) at org.digiplex.bukkitplugin.commander.replacement.ReplacementCommand.executeEffects(ReplacementCommand.java:40) at org.digiplex.bukkitplugin.commander.module.PlayerCommandModule.onPlayerCommandPreprocess(PlayerCommandModule.java:55) at sun.reflect.GeneratedMethodAccessor266.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:339) at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:477) at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:462) at net.minecraft.server.NetServerHandler.handleCommand(NetServerHandler.java:872) at net.minecraft.server.NetServerHandler.chat(NetServerHandler.java:826) at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:808) at net.minecraftserverhook.NetServerHandlerProxy.a(NetServerHandlerProxy.java:124) at net.minecraft.server.Packet3Chat.handle(Packet3Chat.java:44) at net.minecraft.server.NetworkManager.b(NetworkManager.java:282) at net.minecraft.server.NetServerHandler.d(NetServerHandler.java:109) at net.minecraft.server.ServerConnection.b(SourceFile:35) at net.minecraft.server.DedicatedServerConnection.b(SourceFile:30) at net.minecraft.server.MinecraftServer.q(MinecraftServer.java:577) at net.minecraft.server.DedicatedServer.q(DedicatedServer.java:213) at net.minecraft.server.MinecraftServer.p(MinecraftServer.java:473) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:405) at net.minecraft.server.ThreadServerApplication.run(SourceFile:539) Caused by: java.lang.ClassCastException: org.digiplex.bukkitplugin.commander.scripting.EchoControlPlayer cannot be cast to org.bukkit.craftbukkit.entity.CraftPlayer at org.bukkit.craftbukkit.entity.CraftPlayer.showPlayer(CraftPlayer.java:632) at net.h31ix.anticheat.CommandHandler.handleSpy(CommandHandler.java:239) at net.h31ix.anticheat.CommandHandler.onCommand(CommandHandler.java:591) at org.bukkit.command.PluginCommand.execute(PluginCommand.java:40) ... 26 more
If I run "/spy <playername>" a second time right after, it executes fine. Any ideas?
@tustin2121
Wow, fast answer. Thanks! I'll look into that, but I think I had tried already.
EDIT: Doesn't work, unfortunately. Tried with classic color codes &+something and tried with ChatColor.COLOR. Do you plan adding such a feature?
@xou816
If you can somehow make colors in the chat (like with the section symbol, I think), I'd imagine you can do the same thing in Commander's replacements and such. Other than that, it has no special handling for colors. Try it out and see if you can make it work. :P
Hello, Thank you for this plugin! However I have a little question: does it support colors? I couldn't find if it did. If not, could you add that (little) feature? Thanks!
@tustin2121
Ahh okay, perfect, thank you!
@kbryantLA24
Did you not see the response on the ticket? I closed it, so it disappears from the default page; you have to open the filter and tell it to show all tickets.
Copied from there:
Commander has always had this: "commander reload". However, it must be run from the console (to get around all sorts of malarchy with permissions checking and stuff). The logic is that you'll be editing the replacement files on the server anyway (users cant edit scripts or replacements), so reaching the console shouldn't be much more work.
Hi, can you add an in-game command to reload Commander? Instead of having to reload the entire server... Thanks!
This is a great plugin, keep up the good work!
I have updated the ALPHA release to a BETA release, since no one seems to be reporting any major flaws of version 2.0. I still want to complete a decent API before considering it a release.
I have uploaded a new Version 2.0.1, which should be available to you all pending approval. It fixes a few things and adds a few things, which I will be putting into the documentation over on the Pages tab (if I haven't already).
I hope the 190-odd of you who downloaded and tried version 2.0 are liking the new features! Don't hesitate to say something, here, in a PM, or as a ticket, if something doesn't seem right! :)
@TNTUP
Ah, yes, I see now. Yes, you'll have to rely on another plugin to load the text file and do what you want with it. Commander will be able to call that plugin's command though.
@tustin2121
I mean if we can create commands and the command loads the text file. nvm it then
@TNTUP
I am not sure what you are suggesting. What does this "ranks" command do? What is it that you want it to do?
Remember that this plugin is here to facilitate shortcuts to other commands. It doesn't add its own commands (aside from "echo"). You're probably going to have to look to another plugin to add/use a "ranks" command.