Command API thoughts
#1
I don't quite like how command handling is done in plugins currently. I'd like to propose a change to the API that would make it easier to use, more consistent and possibly extensible to other languages.
(Sorry for the weird formatting, it's taken out from my notes text file and the forum doesn't seem to support tabs Sad )

Current state:
==============
cPlugin handles command "adding": cPlugin:AddCommand(Command, Description, Permission)
-- used for listing commands using "/help"
cLuaCommandBinder handles command binding via cPlugin:BindCommand(Command, Permission, Function)
-- used for actual command handling

Problems:
-- Binding and Adding aren't too related - plugin can add command without binding it and bind command without adding it -> mess
-- List of commands is fragmented across cPlugin instances


Proposed solution:
==================
cPlugin won't take care of anything command-related within the API. All command-handling functions will be exported on the cPluginManager object. Therefore if we ever support another language, it will make things easier.
New API functions:
-- cPluginManager:BindCommand(Command, Permission, Function, Description)
---- Binds the command, maintains one global list of commands; knows which plugin to bind to using either the LuaState ptr or a global variable within the LuaState
-- cPluginManager:ForEachCommand(Callback)
---- Calls the callback for each command in the list, thus allowing enumeration, inspection etc.
---- function Callback(Command, Permission, Description[, PluginName?]);
-- cPluginManager:IsCommandBound(Command)
---- Returns true if a command with this name has been bound (to any plugin)
-- cPluginManager:GetCommandPermission(Command)
---- Returns the permission needed for executing the command
-- cPluginManager:ExecuteCommand(Player, Command, Parameters)
---- Executes the command, as if it was requested by the player. Checks permissions first.
-- cPluginManager:ForceExecuteCommand(Player, Command, Parameters)
---- Executes the command, as if it was requested by the player. Doesn't check permissions!


So, what do you think?
Reply
Thanks given by:
#2
seems great Smile
Reply
Thanks given by:
#3
Looks complicated... I'm not entirely sure I get all of itBig Grin

Will I be able to do magic like this:
	Plugin:AddCommand("/money",			" - shows your coins ammount",	"coiny.base")
	Plugin:AddCommand("/m",				" - shortcut for /money",			"coiny.base")
	
	Plugin:BindCommand("/money",	"coiny.base",		HandleMoneyCommand)
	Plugin:BindCommand("/m",		"coiny.base",		HandleMoneyCommand)
??
Reply
Thanks given by:
#4
What kind of magic are you referring to? Actually your code will be much easier in the new API:
Code:
PluginManager:BindCommand("/money", "coiny.base", HandleMoneyCommand, "Shows your coins amount");
PluginManager:BindCommand("/m",     "coiny.base", HandleMoneyCommand, "Shortcut for /money");

Which reminds me - using this API you could actually make a plugin to let players define their own shortcuts, per-player.
Reply
Thanks given by:
#5
Aaaand how do I add the command, that will not be listed in /help? Smile
Reply
Thanks given by:
#6
You couldn't. Why would you want that anyway?

Note that /help already filters out commands for which the player doesn't have permissions.
Reply
Thanks given by:
#7
Quote:Why would you want that anyway?
For example, if I need a shortcut that isn't listed. Or that is described in full command's help string. Or if I'm developing a plugin and absolutely must have numerous debug commands, but I don't want to mess up the /help list.

Permissions is not the point in my case. My point is the ability to make a command that will not be listed, yet which will be usable.

More than that, I might need the ability to have multiple help lines for a single command bind!
For example, I have Portals plugin. I need commands for swapping portal selection mode, for creating a portal entrance and for creating a portal exit. Now, in my mind, the ideal set of commands would be:
/portal mode
/portal enter (name)
/portal exit (name)
But I can't bind something to "/portal xxx", as far as I remember. Therefore I'm forced to either make "/pmode", "/penter" and "/pexit" commands OR make a "/portal" command and handle different cases through command split manually. First option works fine, but looks kinda ugly, the second one left me with no way to document it for /help properly (in your system). And is somewhat messy in terms of dealing with permissions, should I want to have different.

So, let's think about another way to handle it, so I could have both multiple discriptions and hidden commands.
Perhaps, it might be better if we'll work it around so I could even assign different functions to "/portal enter (name)" and "/portal exit (name)" automagically. And different permissions. We really might use some support for multi-word commands.
Reply
Thanks given by:
#8
Actually this is rather easy to solve. We can make it so that when a command has empty help string, it will not display in the /help list. That's all it takes:

For debug purposes, you don't care about the /help list; if you do, just don't provide the help string in command binding.

As for your Portal example, you could achieve that by binding the "portal" command (possibly with an empty help string to hide it), provide the functionality there using a switch on the split. Then, you bind a "portal mode" command with the correct help string and a dummy handler function; "portal enter" and "portal exit" the same. Since MCServer always compares the commands in the internal command table with the first word of the player-issued command, it will never match "portal mode" nor the other two.

Why am I doing this so twisted? Consider for a while if we wanted to add the posibility to bind multi-word commands. A plugin binds "portal mode" command, then another plugin requests to bind "portal" command. Do we let it, or do we refuse? If we let it, how do we handle user input, then? What if the registration is done the other way around, do we accept it, or refuse it?
In my opinion, multi-word commands are just not reasonably implementable; only a single plugin can reasonably cover all the bases, and it can do so on its own using the split.

So, to sum up:
cPluginManager:BindCommand("Command", "Permission", Function, "") - binds the command, but hides it from the help
cPluginManager:BindCommand("Multi Word Command", "Any Permission", DummyFunction, "Description") - displays help, never gets called
Reply
Thanks given by:
#9
Now it sounds clear and reasonable Smile
So, go ahead, break all the plugins!Big Grin
Reply
Thanks given by:
#10
Alright then, I'm gonna try this. Let's hope my Lua-fu is up to this.
Reply
Thanks given by:




Users browsing this thread: 5 Guest(s)