+ Reply to Thread
Page 1 of 2 1 2 LastLast
Results 1 to 15 of 17

Thread: LibSlashCmd - Simplifying and securing slash commands

  1. #1
    Rift Chaser
    Join Date
    Oct 2011
    Posts
    398

    Default LibSlashCmd - Simplifying and securing slash commands

    Hey all. I spent 5 hours start to finish working on the first version of this addon library, and would like to give you all a heads up of its existence.

    Taken from addon description:
    What is LibSlashCmd?
    LibSlashCmd is intended to make handling any and all slash commands simple and worryless. It also has complete slash command clashing protection.


    Features:
    - Same-name command clashing support.
    ex. If you try to register /myaddon but it is already taken, it will (attempt to) register /myaddon2 instead.
    LibSlashCmd supports clashing with any and all RIFT slash commands - even with addons that don't use LibSlashCmd.
    If you use LibSlashCmd, your slash command will always work, no matter how many addons use your exact slash command. (Allows for up to 99 same-name slash commands.)

    - Simplistic infinite arguments and user input support.

    - Your code is (arguably) more organized and easier to read (in comparison to using if/elseif to go through different commands and user input).

    - Simple support for fallbacks. If a user enters an unrecognized command, you can (optionally) point them to any function (ex. a message).


    How to use it:
    With LibSlashCmd, you do not need to worry about registering your command with anything but LibSlashCmd. So no table.insert(Command.Slash.Register("command")...
    With LibSlashCmd, you are not required to have a slash command handling function.

    First, let's register our command with LibSlashCmd, which will then register it with RIFT.
    Code:
    LibSlashCmd.Register("myaddon", "MyAddon")
    The first parameter is the slash command. The second parameter is your addon name. (If the addon name is incorrect, RIFT will complain.)

    The Register method returns the command that you will be using throughout your addon. If your command is already in use by another addon, and clashes, then it may be changed to /command2, /command20, /command99, etc. It will keep trying until it works (from #2 to #99). (If all 99 slash command names are taken, the Register method will return nil.)
    I suggest creating an addon-wide local to store the Register method return value (the command).
    Code:
    local command = nil
    command = LibSlashCmd.Register("myaddon", "MyAddon")
    The LibSlashCmd.Register should be called when your addon is loading/initializing.

    LibSlashCmd.RegisterFunc Examples:
    For this example here, when the user types /myaddon ANYTHING, it will fallback to the default function, and print "default".
    Code:
    local command = nil
    command = LibSlashCmd.Register("myaddon", "MyAddon")
    LibSlashCmd.RegisterFunc(command,
                            "_fallback",
                            function(input)
                                print("default")
                            end)
    It's important to note that the fallback function will only be called if no other functions can be found with the user's input.

    For the next example, when the user types /myaddon tell me ANYTHING, it will print ANYTHING.
    Code:
    local command = nil
    command = LibSlashCmd.Register("myaddon", "MyAddon")
    LibSlashCmd.RegisterFunc(command,
                            "tell me",
                            function(input)
                                message = table.concat(input, " ")
                                print(message)
                            end)
    It's important to note that arguments can have spaces in them. It will still work fine, and work as intended.
    It's also important to note that the function NEEDS to have one argument. That argument is all of the user's input, in a table array, split by one space per value.
    You'll notice that, to get all of the input in one string, I used the table.concat method.
    I could have used input[0] if I just wanted the first word.

    For organization purposes, you may want to put all the RegisterFunc calls into a separate function, and call that function right after you call LibSlashCmd.Register.
    Download at:
    http://www.riftui.com/downloads/info...bSlashCmd.html
    Last edited by TimeBomb; 03-01-2012 at 09:37 PM.

  2. #2
    RIFT Community Ambassador the_real_seebs's Avatar
    Join Date
    Jan 2011
    Posts
    16,859

    Default

    Oooh, interesting.

    I have some overlapping-but-different functionality in LibGetOpt, which provides support for simplified access to argument strings -- no trying to do regexes.

    But LibSlashCommand looks awfully useful to me.
    You can play WoW in any MMO. You don't have to play WoW in RIFT. Oh, and no, RIFT is not a WoW clone. Not having fun any more? Learn to play, noob! I don't speak for Riftui, but I moderate stuff there. Just came back? Welcome back! Here's what's changed. (Updated for 2.5!)

  3. #3
    Plane Touched Verea's Avatar
    Join Date
    Feb 2011
    Location
    Netherlands
    Posts
    200

    Default

    I see something you could change, would also get rid of the '99' commands limit:

    Code:
            local i = 0
            for i = 2, 99 do -- Attempting to see if commandName2-99 are available.
                newCommandName = commandName .. i
                if not LibSlashCmd.storage[newCommandName] then -- newCommandName was available. Using that instead of commandName.
                    finalCommandName = newCommandName
                    break
                end
            end
    Try using a more clever data representation in tables and make more use of for i, cmd in pairs(commands) do ... end

    Not that it's really a concern but, yeah, scalability for the win.
    Verae, level 60 Cleric @ Blightweald, Guild Master of Tea Club
    I want to fly like an eagle, to the sea.
    I want to fly like an eagle, let my spirit carry me.

  4. #4
    Rift Chaser
    Join Date
    Oct 2011
    Posts
    398

    Default

    Quote Originally Posted by Verea View Post
    I see something you could change, would also get rid of the '99' commands limit:

    Code:
            local i = 0
            for i = 2, 99 do -- Attempting to see if commandName2-99 are available.
                newCommandName = commandName .. i
                if not LibSlashCmd.storage[newCommandName] then -- newCommandName was available. Using that instead of commandName.
                    finalCommandName = newCommandName
                    break
                end
            end
    Try using a more clever data representation in tables and make more use of for i, cmd in pairs(commands) do ... end

    Not that it's really a concern but, yeah, scalability for the win.
    I purposely limited it to 99 to help with resource usage. I don't want it looping through, attempting to register a command, more than that many times - I imagine it would use too much resources. If it really does become a problem later on, I may look more increasing it.

  5. #5
    Plane Touched Verea's Avatar
    Join Date
    Feb 2011
    Location
    Netherlands
    Posts
    200

    Default

    Quote Originally Posted by TimeBomb View Post
    I purposely limited it to 99 to help with resource usage. I don't want it looping through, attempting to register a command, more than that many times - I imagine it would use too much resources. If it really does become a problem later on, I may look more increasing it.
    Rest assured that if I can loop through 40 units with all their spell, damage taken, damage done, spell break downs, deaths and more about 200 times per second, you can do that for your slash command lib. ;)
    Verae, level 60 Cleric @ Blightweald, Guild Master of Tea Club
    I want to fly like an eagle, to the sea.
    I want to fly like an eagle, let my spirit carry me.

  6. #6
    Rift Chaser
    Join Date
    Oct 2011
    Posts
    398

    Default

    Quote Originally Posted by Verea View Post
    Rest assured that if I can loop through 40 units with all their spell, damage taken, damage done, spell break downs, deaths and more about 200 times per second, you can do that for your slash command lib. ;)
    Heh, I lifted the limit from 99 to 9999. I don't want to unlimit it as to avoid killing the game's resources and crashing it. If you wish to propose a way to better scale it without the blatant limit as of now, then I am all ears.

    I also fixed a major bug that I missed in my initial round of testing. The specified [command] function wasn't successfully called when their were both arguments and user input. This is now all fixed up.

    Version 0.2 is available on riftui.com. I'll be releasing it to Curse within the next week or two, allowing me to weed out any final bugs and put up any final updates before the Curse release.


    On a side note, I'm currently working on writing up a cooldown action bar overlay addon. It seems to be possible - but the possible level of intuitiveness is not that of what many users may feel comfortable with. You'll have to manually enter in the ability name, and manually place where the cooldown number will go. I'll be doing my best to make this as painless as possible, though.
    Last edited by TimeBomb; 03-06-2012 at 01:47 PM.

  7. #7
    Rift Chaser
    Join Date
    Oct 2011
    Posts
    398

    Default

    Updated to version 0.3, on riftui.com.

    As of version 0.3, LibSlashCmd.InvokeFunc is now available.
    It allows the developer to invoke a command function from the code with ease.
    Example:
    Code:
    LibSlashCmd.InvokeFunc("myaddon", "tell me", "This is a dev test.")
    This will produce the same result as if the user typed /myaddon tell me This is a dev test.
    This makes debugging, and handling certain scenarios, ex. preset configurations, much easier.
    Use less code, and keep the code you are using more consistant. This is one factor that makes LibSlashCmd.InvokeFunc so powerful.

  8. #8
    Plane Touched Verea's Avatar
    Join Date
    Feb 2011
    Location
    Netherlands
    Posts
    200

    Default

    Quote Originally Posted by TimeBomb View Post
    Updated to version 0.3, on riftui.com.
    What's the difference to putting

    mySlashCommandHandler("blah this is", "a couple of", "arguments")

    somewhere in your code for testing?
    Verae, level 60 Cleric @ Blightweald, Guild Master of Tea Club
    I want to fly like an eagle, to the sea.
    I want to fly like an eagle, let my spirit carry me.

  9. #9
    Rift Chaser
    Join Date
    Oct 2011
    Posts
    398

    Default

    Quote Originally Posted by Verea View Post
    What's the difference to putting

    mySlashCommandHandler("blah this is", "a couple of", "arguments")

    somewhere in your code for testing?
    With LibSlashCmd, a method for handling slash commands is not needed.
    Feel free to take a quick look at the addon description on riftui.com, it describes (and provides examples of) how LibSlashCmd's methods are used.

  10. #10
    Plane Touched
    Join Date
    Feb 2012
    Posts
    228

    Default

    Quote Originally Posted by Verea View Post
    What's the difference to putting

    mySlashCommandHandler("blah this is", "a couple of", "arguments")

    somewhere in your code for testing?
    TimeBomb's approach could be useful for unit testing.

    Also, there's potential for LibSlashCmd to parse the input arguments before calling the command handler (don't know if it does it yet), easing development for us.

  11. #11
    Rift Chaser
    Join Date
    Oct 2011
    Posts
    398

    Default

    Quote Originally Posted by Baanano View Post
    TimeBomb's approach could be useful for unit testing.

    Also, there's potential for LibSlashCmd to parse the input arguments before calling the command handler (don't know if it does it yet), easing development for us.
    Currently, when a command is sent via the user's slash command input or the developer's InvokeFunc call, the function is found, the input is split by spaces and put into a table, and the function is called while passing the input table into the function.

    Anything else, validation included, is intended to be handled by the addon-specific defined functions (via the RegisterFunc method).

    One of the biggest features or 'reasons to use' LibSlashCmd in my opinion is the clashing support. The arguably easier handling of functions and user input is just a plus. The InvokeFunc makes it easier to do certain tasks; debugging slash commands being one of them.
    In terms of making it easier to debug and test? It's by no means the main focus of this library, but I'm all ears.
    Last edited by TimeBomb; 03-09-2012 at 03:12 AM.

  12. #12
    Plane Touched Verea's Avatar
    Join Date
    Feb 2011
    Location
    Netherlands
    Posts
    200

    Default

    Not to discredit your idea here, but I would just like to make a quick notion on how unlikely it is to have clashing add-on names in most cases.

    If everyone add-on kept their /command equal to their add-on name (which is always unique, as you can't have two add ons with the same name), no clashes would ever happen. Right?

    Just a thought from me.
    Verae, level 60 Cleric @ Blightweald, Guild Master of Tea Club
    I want to fly like an eagle, to the sea.
    I want to fly like an eagle, let my spirit carry me.

  13. #13
    Plane Walker Kreiri's Avatar
    Join Date
    Feb 2011
    Posts
    402

    Default

    Quote Originally Posted by Verea View Post
    Not to discredit your idea here, but I would just like to make a quick notion on how unlikely it is to have clashing add-on names in most cases.
    About as unlikely as falling on a slippery icy road.

    Quote Originally Posted by Verea View Post
    If everyone add-on kept their /command equal to their add-on name (which is always unique,
    o rly?

    Quote Originally Posted by Verea View Post
    as you can't have two add ons with the same name)
    Citation needed.
    Feminism is the radical notion that women are people.

  14. #14
    Plane Walker Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    439

    Default

    Quote Originally Posted by Kreiri View Post
    Citation needed.
    or... put two addons with the same identifier in your addons folder: only one of them shows up in the character selection addons list.

    Same name is fine, but not same identifier.

  15. #15
    RIFT Community Ambassador the_real_seebs's Avatar
    Join Date
    Jan 2011
    Posts
    16,859

    Default

    There are often cases where people would rather have a shorter name; LootSorter uses /ls, for instance. (On my list: Change LibGetOpt's slash command creator to take a table of names in order of preference.)
    You can play WoW in any MMO. You don't have to play WoW in RIFT. Oh, and no, RIFT is not a WoW clone. Not having fun any more? Learn to play, noob! I don't speak for Riftui, but I moderate stuff there. Just came back? Welcome back! Here's what's changed. (Updated for 2.5!)

+ Reply to Thread
Page 1 of 2 1 2 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts