As of (the upcoming) ULX 3.5, the command system has been totally re-written in a way that allows for much greater flexibility
and though it may not seem so at first, I feel it is much easier to create commands/modules once you've gotten the hang of it.
Some community members have stated that it is complicated to understand -
http://forums.ulyssesmod.net/index.php/topic,4319.msg16888.html#msg16888 -
and are of the opinion that ULX wasn't meant to be built upon. -
http://forums.ulyssesmod.net/index.php/topic,3324.msg16925.html#msg16925Though ULX wasn't written to build an entire system on like ULib could be, ULX WAS made to be able to add additional commands and functions
that would/could allow greater functionality of administrating your server.
Why else would we have a Modules folder within ULX?
Since ULX doesn't have anywhere near the documentation of ULib -
http://www.ulyssesmod.net/docs -, I'm writing this post as a general tutorial
as to how the new (as of ULX 3.5 (currently in SVN)) command system works.
For comparison, the first few examples will show the OLD (ULX <= v3.4) code for adding a command.
[OLD STUFF}
ulx.concommand( "<STRING - command used to execute, 'ulx <this>'>", <literal name of function, ulx>, "<STRING - help command that would show in 'ulx help'", <Default access required to perform command, example 'ULib.ACCESS_SUPERADMIN'>, "!<STRING - chat command used to perform function>", _(I forget, hide chat string/Boolean?), ulx.ID_PLAYER_HELP (Forget this too) )
ulx.addToMenu( ulx.<menu to add to, ex MCLIENT>, "<STRING - Name of command you wanted in menu", "console command to run, example 'ulx <this>'" )
Then, an old function using above style
ulx.setCategory( "<STRING> - Name of help category function(s) will fall under" )
function ulx.<name of your function>( <player object (who called the command)>, <command called>, <table of arguments after command>, <actual full string after command> )
...Do Stuff with passed variables...
end
The above should look simple to most lua developers, if not perhaps long.
Using the old command system, the below example from MrPresident's release, ULX EXPLODE, shows the variables being interacted with within ULX.
I've heavily commented so those less familiar with Lua, or at least our use of it in ULX, can follow along.
ulx.setCategory( "Fun" ) -- Set category for help function
function ulx.cc_explode( ply, command, argv, args )
if #argv < 1 then -- Check to make sure the player typing "ulx explode" typed MORE than just that.
ULib.tsay( ply, ulx.LOW_ARGS, true ) -- Give them the default low argument warning (did you know ULX had one? :P)
return -- stop any further functions
end
local targets, err = ULib.getUsers( argv[ 1 ], _, true, ply ) -- Check argument 1, see if a player, ULib.getUsers returns targets or an error.
if not targets then -- Make sure targets was returned with one or more players.
ULib.tsay( ply, err, true ) -- If not, return error
return -- stop any further action
end
local dmg = tonumber( argv[ 2 ] ) or 250 -- Set damage to number after the player name, 2nd argument past "explode", or default to 250
local radius = tonumber( argv[ 3 ] ) or 150 -- Set radius to number after the damage, 3rd argument past "explode", or default to 150
if dmg < 0 then -- return an error if less than 0
ULib.tsay( ply, "Damage must be above 0", true )
return
end
if radius > 10000 or radius < 0 then -- return an error if radius is above 10000 and less than 0.
ULib.tsay( ply, "Radius must be between 0 and 10000", true )
return
end
--... Do Gmod Lua effects stuff with all of the above variables ...
end
Before going into the new stuff.. make some mental notes.
Though the above looks easy enough, which it is, remember that, when properly written, every single "well written" ulx function made by Team Ulysses or anyone else would include all of that code above. All the checks and balances would be required to be done within each function before the "Do Stuff". For every variable necessary, code would be required to make sure there's a default or error out.
Easy? Sure! But bulky. Can you imagine 30+ functions, each one checking to make sure that argument 1 was typed, and had a player involved?
Even more checks if numbers/coordinates/whatever were expected after a valid players name.
[NEW STUFF HERE]So, on to the new New command structure...
ULib's documentation regarding shared command system explains MUCH of the below literal code functions;
See
http://ulyssesmod.net/docs/files/lua/ulib/shared/commands-lua.htmlCommented function -
function ulx.<your_function>( calling_ply, parm1, parm2, parm... )
-- Do code stuff with calling_ply and or parm1,2,...
-- LESS CHECKS NECESSARY!!! -- Function optimization at its finest! The command object sets up the checks!
end
Somewhat commented function setup for ULX 3.5+ (again, see the ULib commands link above for more info)
The following was derived from MrPresident's "ulx explode" parameters
local <name of object, best if same as command> = ulx.command( "<STRING- help category, ex Fun>", "<STRING - console command, example 'ulx <this>'>", <literal function name>, "<STRING - command used in chat to perform action>, <BOOLEAN-hide saychat or not>, <BOOLEAN-require spaces after command or not> )
<name of object>:addParam{ type=ULib.cmds.PlayersArg } -- allows and requires player to input one or more players.
<name of object>:addParam{ type=ULib.cmds.NumArg, min=<min number>, max=<max number>, default=<default number>, hint="<STRING to show during ULX's error assistance", ULib.cmds.optional--<, ULib.cmds.round } -- Add additional number argument, optional, with min/max, and default.
<name of object>:defaultAccess( ULib.ACCESS_ADMIN ) -- Register ULX minimum required default access. In this case, admin
<name of object>:help( "<STRING - command to show in help menu for those with access to this command>" ) -- show this in previously set (in ulx.command) "help" category
<name of object>:logString( "Formatted strnig - Example. "#1s did something to #2s with #3i numbers" ) -- ULX log file and chat. Yes, this can be tricky. Just remember that each addParam command you add is in order. #1, #2, .. above. #1 is always player performing action. #1s makes it a string (see the s after 1). #2 using this code block example is player being acted on, #2s = string. #3i = integer (see type=ULib.cmds.NumArg?)
ulx.addToMenu( ulx.ID_MCLIENT, "<STRING - show this in menu>", "<STRING - console command, example 'ulx <this>'>" )
Below was the SVN/ULX 3.5 version function code requirement for Mr President's ulx explode
function ulx.explode( calling_ply, target_plys, dmg, radius )
-- calling_ply is always passed. The other params? Only passed if you set up the command object to do so!
-- ...Do code stuff with calling player to target player with damage in radius
-- LESS CHECKS NECESSARY!!! -- Fun Fun!
end
Below is the new SVN function setup for ulx explode
local explode = ulx.command( "Fun", "ulx explode", ulx.explode, "!explode" )
explode:addParam{ type=ULib.cmds.PlayersArg }
explode:addParam{ type=ULib.cmds.NumArg, min=0, max=50000, default=250, hint="damage", ULib.cmds.optional, ULib.cmds.round }
explode:addParam{ type=ULib.cmds.NumArg, min=0, max=10000, default=150, hint="radius", ULib.cmds.optional, ULib.cmds.round }
explode:defaultAccess( ULib.ACCESS_ADMIN )
explode:help( "Explodes target(s) with given <damage> and <radius> blast area [Danger - could hurt other players!]" )
explode:logString( "#1s exploded #2s with #3i damage in a #4i radius blast area" )
ulx.addToMenu( ulx.ID_MCLIENT, "Explode", "ulx explode" )
In effect, MrPresident's ~20 lines of error checking and parameter setup have been reduced to 8.
Though not every function written on old command system may 'shrink' as much, we believe the changes are helpful over all.
A good example from a code standings discussion -
http://forums.ulyssesmod.net/index.php/topic,1217.msg17351.html#msg17351In September of 2007, ULX's fun.lua had 1230 lines of code.
In December of 2009, ULX's fun.lua had 693
What some may find even more interesting is that, if I recall correctly, we've added a few more 'fun' commands since 2007.