System Cmd

Nestharus

o-o
Reaction score
84
Why did I make this with other Command Parsers out there?
  • This one uses OO and procedural style
  • This one does not have an actual parser built into it
  • This one has command instancing of root commands (-give might have 10 instances)
  • This one allows specific instances of commands to be enabled/disabled
  • This one provides access flags for specific instances of commands
  • This can handle 8191 different commands each with 8191 different instances as well as 8191 different shells. That is 8191^2+8191 total objects

So yea, this one is a little more complicated than the norm... but it gives you some more flexibility.

plans
Adding enabled operator to root commands and shells.

changelog
1.2.0.0
Added procedural API and updated Demo to include it

Simpler functionality, but same functionality of command and shell objects can be achieved.

Removed some extra checks
1.1.0.1
Added stringType to args

Updated demo
1.1.0.0
Added shell support and new directives (take a look at header)

Added MIN_ARGS and MAX_ARGS to Command module
Made Shell module

Updated demo code to be more insightful in game (you don't need to read demo code before hand now)
1.0.1.1
merged hashtables to one hashtable
1.0.1.0
Added an if statement to AUTO_ENABLE so that it wouldn't run through the loop if AUTO_ENABLE was false. Didn't make it static if as the boolean isn't part of the library that the module is in, meaning that it'd always end up returning false.

Added evaluation

Moved COMMAND and EVALUATION globals to the top of the script

Added an Evaluation command to the demonstration (a simple calculator that supports +, -, *, and /)

JASS:
library Cmd uses StringParser
//StringParser thehelper.net/forums/showthread.php?t=152352

//Version: 1.2.0.0
//Author: Nestharus

globals
    //COMMAND character is the character a string has to start with to be regarded
    //as a command
    private constant string COMMAND = "-"
    
    //EVAL is the character coupled with a command to turn it into an evaluation statement
    //EVAL+COMMAND
    //default is !-
    private constant string EVAL = "!"
    
    //SHELL will change the current group of eval commands
    //SHELL+COMMAND with arg will change current shell to specified shell. If shell doesn't exist, just disables
    //SHELL+COMMAND alone will output current shell
    //SHELL alone will ouput list of shells
    private constant string SHELL = "#"

//Directive API (symbols based on above settings)
//      -command args
//          runs command for trigger player
//
//      -
//          lists commands to trigger player
//
//      #
//          lists shells to trigger player
//
//      #-
//          displays current shell for trigger player to trigger player
//
//      #-shell
//          changes current shell for trigger player
//
//      !-string
//          evaluates string on trigger player's current shell
endglobals

////////////////////////////////////////////////////////////////////////
//Description
//      Cmd allows you to register commands that players can type in game.
//
//      What makes Cmd unique?
//          1. Has an OO API (Command/Shell objects that implement a module and interface)
//          2. Allows command objects to be enabled/disabled while still running through
//             the same root command (2 command objects for -give and only 1 enabled)
//          3. Full access restriction for each player for each specific command object
//             (admin might get access to an extra feature on the -give command)
//          4. Many command libraries use some freaky array syntax. This one uses
//             a stack.
//          5. Has both regular commands and evaluations
//          6. Has shell support (different evaluations)
//          7. Has a more basic procedural API that does not have access restrictions
////////////////////////////////////////////////////////////////////////
//API
//      function CreateShell takes string shell, boolexpr c returns integer
//          Creates a shell
//
//      function SetShell takes string shell, integer playerId returns nothing
//          Sets shell for player
//
//      function GetRootCommand takes string command returns integer
//          Get root command id (root command is the string command)
//
//      function CreateCommand takes integer root, boolean autoEnable, boolexpr c returns integer
//          Creates a command instance of a root command and returns that instance
//
//      function IsCommandEnabled takes integer root, integer command returns boolean
//          Is the command instance enabled?
//
//      function EnableCommand takes integer root, integer command, boolean enable returns nothing
//          Enables a specific command instance
//
//      function GetArgs takes integer root returns Args
//          Returns Args struct for root command
//
//      function GetShellArgs takes integer shell returns string
//          Returns string argument for shell
//
//      function GetCaller takes integer root returns player
//          Returns the player that called the command
//
//      function GetCallerId takes integer root returns integer
//          Returns the id of the player that called the command
//
//      function GetShellCaller takes integer shell returns player
//          Returns the player that called the shell
//
//      function GetShellCallerId takes integer shell returns integer
//          Returns the id of the player that called the shell
//
//      Command Interface (auto required when implementing Command)
//          private static constant string COMMAND_NAME
//              The name of the command (cannot be null or "")
//
//          private static constant boolean AUTO_ENABLE
//              Should it auto enable?
//
//          private static constant boolean AUTO_ACCESS
//              Should players automatically be given access?
//
//          private static constant integer MIN_ARGS
//              Minimum args required to run
//
//          private static constant integer MAX_ARGS
//              Maximum args allowed for running (less than 0 is infinite)
//
//          private static method run takes player caller, integer callerId, Args args returns nothing
//              The method that runs when the command is executed
//
//      Shell Interface (auto required when implementing Shell)
//          private static constant boolean AUTO_ACCESS
//              Should players automatically be given access to shell?
//
//          private static constant string SHELL_NAME
//             The name of the shell (cannot be null or ""). Shells cannot be layered.
//
//      Command Module
//          This must be implemented into your struct to turn it into a command object
//
//          public static boolean enabled
//              enables and disables the command object
//
//          public static method operator [] takes integer playerId returns boolean
//          public static method operator []= takes integer playerId, boolean canUse returns nothing
//              Gets and sets player access to the command
//
//      Shell Module
//          public static method operator [] takes integer playerId returns boolean
//          public static method operator []= takes integer playerId, boolean canUse returns nothing
//              Gets and sets player access to the shell
//
//      struct Args extends array
//          This is the structure that contains arguments
//          StringParser is suggested for inferring argument types
//          A processing method with static fields is suggested for
//          Processing the arguments into a usable form, otherwise
//          the run method will be messy
//
//          public method operator next takes nothing returns thistype
//              Get the next argument on the stack
//
//              Demo-
//                  set args = args.next
//
//          public method operator value takes nothing returns string
//              Get the value of the argument
//              You can use StringType.typeof and StringType.compare to properly
//              determine whether your method should run or not
//
//          public method operator count takes nothing returns integer
//              Get how many arguments there are left on the stack
//              Useful if your command should only take specific arguments
//
//          public method operator stringType takes nothing returns integer
//              Returns the data type of the argument (integer, real, etc)
////////////////////////////////////////////////////////////////////////
    //used to create Commands
    private struct CommandX extends array
        private static trigger commandTrigger = CreateTrigger()
        private trigger command
        private trigger eval
        private static integer array curShell
        private string shellName
        private string commandName
        private static hashtable table = InitHashtable()
        
        private static integer instanceCount = 0
        private static integer shellInstanceCount = 0
        private integer cInstanceCount
        
        //public fields
        private integer playerIdX
        private player playerX
        private StringStack argsX
        
        private integer playerIdS
        private player playerS
        private string argsS
        
        public method operator playerIdShell takes nothing returns integer
            return playerIdS
        endmethod
        
        public method operator playerShell takes nothing returns player
            return playerS
        endmethod
        
        public method operator argShell takes nothing returns string
            return argsS
        endmethod
        
        private method operator playerShell= takes player p returns nothing
            set playerS = p
            set playerIdS = GetPlayerId(p)
        endmethod
        
        private method operator argShell= takes string s returns nothing
            set argsS = s
        endmethod
        
        public method operator playerId takes nothing returns integer
            return playerIdX
        endmethod
        
        public method operator player takes nothing returns player
            return playerX
        endmethod
        
        private method operator player= takes player p returns nothing
            set playerX = p
            set playerIdX = GetPlayerId(p)
        endmethod
        
        public method operator args takes nothing returns StringStack
            return argsX
        endmethod
        
        private method operator args= takes StringStack val returns nothing
            set argsX = val
        endmethod
        
        public method isEnabled takes thistype commandId returns boolean
            return HaveSavedHandle(table, commandId, this)
        endmethod
        
        public method enable takes thistype commandId, boolean b returns nothing
            if (this != 0 and HaveSavedHandle(table, commandId, this) != b) then
                if (b) then
                    call SaveTriggerConditionHandle(table, commandId, this, TriggerAddCondition(commandId.command, LoadBooleanExprHandle(table, commandId, this*-1)))
                else
                    call TriggerRemoveCondition(commandId.command, LoadTriggerConditionHandle(table, commandId, this))
                    call RemoveSavedHandle(table, commandId, this)
                endif
            endif
        endmethod
        
        private static method execute takes nothing returns boolean
            local string command
            //filter out any white space
            local string input = FilterString(GetEventPlayerChatString(), " ", true)
            local StringStack args
            local thistype commandStruct
            local integer i
            local player triggerPlayer = GetTriggerPlayer()
            local integer triggerPlayerId = GetPlayerId(triggerPlayer)
            
            //check to see if the beginning of the string is COMMAND
            if (input == SHELL) then
                set i = 1
                loop
                    exitwhen thistype(i).shellName == null
                    call DisplayTextToPlayer(triggerPlayer, 0, 0, "Shell: " + thistype(i).shellName)
                    set i = i + 1
                endloop
            elseif (input == COMMAND) then
                set i = instanceCount
                loop
                    exitwhen i == 0
                    call DisplayTextToPlayer(triggerPlayer, 0, 0, "Command: " + thistype(i).commandName)
                    set i = i - 1
                endloop
            elseif (SubString(input, 0, 1) == COMMAND) then
                //if it is, filter out all COMMAND chars at the start
                set input = FilterString(input, COMMAND, true)
                //create string stack (easier to get command out)
                set args = StringStack.create(input, StringStack.ARG_DELIMITER)
                //first thing on the stack is the command
                set command = StringCase(args.value, false)
                set args = args.pop() //pop off the command
                
                set commandStruct = LoadInteger(table, StringHash(command), 0)
                //if command exists and is enabled then go on
                if (commandStruct > 0) then
                    set commandStruct.player = GetTriggerPlayer()
                    set commandStruct.args = args
                    call TriggerEvaluate(commandStruct.command)
                endif
                call args.destroy()
            //otherwise check to see if it's an evaluation
            //evaluation should only be used for in-game scripting
            elseif (SubString(input, 0, 2) == EVAL+COMMAND and curShell[triggerPlayerId] != 0) then
                //as args is all one string in this case, the command cannot be deciphered
                //the root command is treated as "eval"
                set commandStruct = curShell[triggerPlayerId]
                set commandStruct.playerShell = triggerPlayer
                set commandStruct.argShell = SubString(input, 2, StringLength(input))
                call TriggerEvaluate(commandStruct.eval)
            elseif (SubString(input, 0, 2) == SHELL+COMMAND) then
                set input = FilterString(SubString(input, 2, StringLength(input)), " ", true)
                if (input == null or input == "") then
                    if (curShell[triggerPlayerId] != 0) then
                        call DisplayTextToPlayer(triggerPlayer, 0, 0, "Shell: " + thistype(curShell[triggerPlayerId]).shellName)
                    else
                        call DisplayTextToPlayer(triggerPlayer, 0, 0, "Shell: null")
                    endif
                else
                    set curShell[triggerPlayerId] = LoadInteger(table, 0, StringHash(StringCase(input, false)))
                    debug if (curShell[triggerPlayerId] != 0) then
                        debug call DisplayTextToPlayer(triggerPlayer, 0, 0, "shell: " + thistype(curShell[triggerPlayerId]).shellName)
                    debug else
                        debug call DisplayTextToPlayer(triggerPlayer, 0, 0, "shell: null")
                    debug endif
                endif
            endif
            
            set triggerPlayer = null
            return false
        endmethod
            
        public static method operator [] takes string commandName returns integer
            local thistype this = 0
            if (commandName != "" and commandName != null) then
                set this = LoadInteger(table, StringHash(commandName), 0)
                if (this == 0) then
                    set instanceCount = instanceCount + 1
                    set this = instanceCount
                    set command = CreateTrigger()
                    set this.commandName = commandName
                    call SaveInteger(table, StringHash(commandName), 0, this)
                endif
            endif
            return this
        endmethod
        
        public static method registerShell takes string shell, boolexpr c returns integer
            local thistype this = 0
            if (shell != "" and shell != null and not HaveSavedInteger(table, 0, StringHash(shell))) then
                set shellInstanceCount = shellInstanceCount + 1
                set this = shellInstanceCount
                set eval = CreateTrigger()
                call TriggerAddCondition(eval, c)
                call SaveInteger(table, 0, StringHash(shell), this)
                set shellName = shell
            endif
            
            return this
        endmethod
        
        public method register takes boolexpr c returns thistype
            if (this != 0) then
                set cInstanceCount = cInstanceCount + 1
                call SaveBooleanExprHandle(table, this, cInstanceCount*-1, c)
                return cInstanceCount
            endif
            return 0
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer i = 12
            local player p
            debug if (COMMAND != EVAL and COMMAND != SHELL and EVAL != SHELL) then
                loop
                    set i = i - 1
                    set p = Player(i)
                    if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(p) == MAP_CONTROL_USER) then
                        call TriggerRegisterPlayerChatEvent(commandTrigger, p, COMMAND, false)
                        call TriggerRegisterPlayerChatEvent(commandTrigger, p, SHELL, true)
                    endif
                    
                    exitwhen i == 0
                endloop
                call TriggerAddCondition(commandTrigger, Condition(function thistype.execute))
            debug else
                debug if (COMMAND == EVAL) then
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Command Library Failure: COMMAND equals EVAL")
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, COMMAND + "==" + EVAL)
                debug endif
                debug if (COMMAND == SHELL) then
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Command Library Failure: COMMAND equals SHELL")
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, COMMAND + "==" + SHELL)
                debug endif
                debug if (EVAL == SHELL) then
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Command Library Failure: EVAL equals SHELL")
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, EVAL + "==" + SHELL)
                debug endif
            debug endif
        endmethod
        
        public static method setShell takes string shell, integer playerId returns nothing
            set curShell[playerId] = LoadInteger(table, 0, StringHash(shell))
        endmethod
    endstruct
    
    struct Args extends array
        public method operator next takes nothing returns thistype
            return StringStack(this).next
        endmethod
        
        public method operator value takes nothing returns string
            return StringStack(this).value
        endmethod
        
        public method operator count takes nothing returns integer
            return StringStack(this).count
        endmethod
        
        public method operator stringType takes nothing returns integer
            return StringStack(this).stringType
        endmethod
    endstruct
    
    //Procedural API
    function GetArgs takes CommandX root returns Args
        return root.args
    endfunction
    
    function GetShellArgs takes CommandX shell returns string
        return shell.argShell
    endfunction
    
    function EnableCommand takes CommandX root, CommandX command, boolean enable returns nothing
        call command.enable(root, enable)
    endfunction
    
    function IsCommandEnabled takes CommandX root, CommandX command returns boolean
        return command.isEnabled(root)
    endfunction
    
    function GetRootCommand takes string command returns integer
        return CommandX[StringCase(FilterString(FilterString(command, COMMAND, true), " ", true), false)]
    endfunction
    
    function CreateCommand takes CommandX root, boolean autoEnable, boolexpr c returns integer
        local CommandX command = 0
        if (root != 0) then
            set command = root.register(c)
            call EnableCommand(root, command, autoEnable)
        endif
        return command
    endfunction
    
    function GetCaller takes CommandX root returns player
        return root.player
    endfunction
    
    function GetCallerId takes CommandX root returns integer
        return root.playerId
    endfunction
    
    function GetShellCaller takes CommandX shell returns player
        return shell.playerShell
    endfunction
    
    function GetShellCallerId takes CommandX shell returns integer
        return shell.playerIdShell
    endfunction
    
    function CreateShell takes string shell, boolexpr c returns integer
        return CommandX.registerShell(StringCase(FilterString(FilterString(shell, COMMAND, true), " ", true), false), c)
    endfunction
    
    function SetShell takes string shell, integer playerId returns nothing
        call CommandX.setShell(shell, playerId)
    endfunction
    
    module Command
        private static CommandX command
        private static CommandX root
        private static boolean array access
        
        public static method operator enabled takes nothing returns boolean
            return command.isEnabled(root)
        endmethod
        
        public static method operator enabled= takes boolean b returns nothing
            call command.enable(root, b)
        endmethod
        
        public static method operator [] takes integer id returns boolean
            return access[id]
        endmethod
        
        public static method operator []= takes integer id, boolean b returns nothing
            set access[id] = b
        endmethod
        
        private static method execute takes nothing returns boolean
            if (access[root.playerId] and root.args.count >= MIN_ARGS and (MAX_ARGS < 0 or root.args.count <= MAX_ARGS)) then
                call thistype.run(root.player, root.playerId, root.args)
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer i
            set root = CommandX[StringCase(FilterString(FilterString(COMMAND_NAME, COMMAND, true), " ", true), false)]
            if (root != 0) then
                set command = root.register(Condition(function thistype.execute))
                set enabled = AUTO_ENABLE
                if AUTO_ACCESS then
                    set i = 12
                    loop
                        set i = i - 1
                        set access<i> = AUTO_ACCESS
                        exitwhen i == 0
                    endloop
                endif
            debug else
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, &quot;Command Library Failure: Invalid Command Name&quot;)
            endif
        endmethod
    endmodule
    
    module Shell
        private static CommandX shell
        private static boolean array access
        
        public static method operator [] takes integer id returns boolean
            return access[id]
        endmethod
        
        public static method operator []= takes integer id, boolean b returns nothing
            set access[id] = b
        endmethod
        
        private static method execute takes nothing returns boolean
            if (access[shell.playerIdShell]) then
                call thistype.run(shell.playerShell, shell.playerIdShell, shell.argShell)
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer i
            set shell = CommandX.registerShell(StringCase(FilterString(FilterString(SHELL_NAME, COMMAND, true), &quot; &quot;, true), false), Condition(function thistype.execute))
            if shell != 0 and AUTO_ACCESS then
                set i = 12
                loop
                    set i = i - 1
                    set access<i> = AUTO_ACCESS
                    exitwhen i == 0
                endloop
            debug else
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, &quot;Command Library Failure: Invalid Shell Name&quot;)
            endif
        endmethod
    endmodule
endlibrary
</i></i>


Demo Code
JASS:
scope CmdDemo initializer ini
    //////////////////////////////////////////////////////////////////////////////////////////
    //Procedural API Demo with same functionality as Command object
    //This is more complicated than minimum because of the Command object
    //features
    globals
        private integer subtractRoot
        private integer subtractInstance
        private boolean array subtractPlayerAccess
    endglobals
    
    private function Subtract takes nothing returns boolean
        local Args args = GetArgs(subtractRoot)
        local player p = GetCaller(subtractRoot)
        local integer pId = GetCallerId(subtractRoot)
        local integer i
        local integer i2
        
        //the if statement to get the same functionality as a command object
        if (subtractPlayerAccess[pId] and args.count &gt;= 1 and args.count &lt;= 2) then
            if (args.count == 2) then
                if (StringType.compare(args.stringType, StringType.INTEGER))then
                    set i = S2I(args.value)
                    set args = args.next
                    if (StringType.compare(args.stringType, StringType.INTEGER))then
                        set i2 = S2I(args.value)
                        call DisplayTextToPlayer(p, 0, 0, &quot;subtract: &quot; + I2S(i-i2))
                    endif
                endif
            elseif (args.value == &quot;?&quot;) then
                call DisplayTextToPlayer(p, 0, 0, &quot;subtracts two integers&quot;)
                call DisplayTextToPlayer(p, 0, 0, &quot;args: int int&quot;)
            endif
        endif
        
        return false
    endfunction
    
    private function IniSubtract takes nothing returns nothing
        local integer i = 12
        set subtractRoot = GetRootCommand(&quot;subtract&quot;)
        set subtractInstance = CreateCommand(subtractRoot, true, Condition(function Subtract))
        loop
            set i = i - 1
            set subtractPlayerAccess<i> = true
            exitwhen i == 0
        endloop
    endfunction
    //////////////////////////////////////////////////////////////////////////////////////////
    //Command Object Demonstrations
    struct AddCmd extends array
        private static constant string COMMAND_NAME = &quot;add&quot;
        private static constant boolean AUTO_ENABLE = true
        private static constant boolean AUTO_ACCESS = true
        private static constant integer MIN_ARGS = 1
        private static constant integer MAX_ARGS = 2
        
        private static integer i
        private static integer i2
        
        private static method process takes Args args returns boolean
            if (StringType.compare(args.stringType, StringType.INTEGER))then
                set i = S2I(args.value)
                set args = args.next
                if (StringType.compare(args.stringType, StringType.INTEGER))then
                    set i2 = S2I(args.value)
                    return true
                endif
            endif
            return false
        endmethod
        
        private static method run takes player caller, integer callerId, Args args returns nothing
            if (args.count == 2) then
                if (process(args)) then
                    call DisplayTextToPlayer(caller, 0, 0, &quot;add 1: &quot; + I2S(i+i2))
                endif
            elseif (args.value == &quot;?&quot;) then
                call DisplayTextToPlayer(caller, 0, 0, &quot;Adds two integers together&quot;)
                call DisplayTextToPlayer(caller, 0, 0, &quot;args: int int&quot;)
            endif
        endmethod
        
        implement Command
    endstruct

    struct AddCmd2 extends array
        private static constant string COMMAND_NAME = &quot;add&quot;
        private static constant boolean AUTO_ENABLE = true
        private static constant boolean AUTO_ACCESS = true
        private static constant integer MIN_ARGS = 1
        private static constant integer MAX_ARGS = 2
        
        private static string s
        
        private static method run takes player caller, integer callerId, Args args returns nothing
            if (args.count == 2) then
                call DisplayTextToPlayer(caller, 0, 0, &quot;add 2: &quot; + args.value+args.next.value)
                
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, &quot;Disabling command 2&quot;)
                set enabled = false
            elseif (args.value == &quot;?&quot;) then
                call DisplayTextToPlayer(caller, 0, 0, &quot;Adds two strings together&quot;)
                call DisplayTextToPlayer(caller, 0, 0, &quot;args: string string&quot;)
            endif
        endmethod
        
        implement Command
    endstruct
    //////////////////////////////////////////////////////////////////////////////////////////
    //Shell object demonstration
    struct EvalSimple extends array
        private static constant boolean AUTO_ACCESS = true
        private static constant string SHELL_NAME = &quot;CALCULATOR&quot;
        
        private static real evaluation
        
        private static real array nums
        private static string array operators
        private static integer array priority
        private static integer count
        private static integer passover
        private static thistype next
        
        private static method eval takes string stringArgs returns boolean
            local StringStack args = StringStack.createByType(stringArgs, &quot; &quot;)
            local string op
            local boolean findOp = false
            local real val
            local boolean processed = false
            set count = 0
            loop
                if (args == 0 and findOp) then
                    set processed = true
                endif
                
                exitwhen args == 0
                if (not findOp) then
                    if (StringType.compare(args.stringType, StringType.REAL)) then
                        set nums[count] = S2R(args.value)
                    else
                        exitwhen true
                    endif
                    set findOp = true
                else
                    set op = args.value
                    if (op == &quot;/&quot; or op == &quot;*&quot;) then
                        set args = args.pop()
                        if (args != 0 and StringType.compare(args.stringType, StringType.REAL)) then
                            if (op == &quot;/&quot;) then
                                set nums[count] = nums[count] / S2R(args.value)
                            elseif (op == &quot;*&quot;) then
                                set nums[count] = nums[count] * S2R(args.value)
                            endif
                        else
                            exitwhen true
                        endif
                    elseif (op == &quot;+&quot; or op == &quot;-&quot;) then
                        set operators[count] = op
                        set count = count + 1
                        set findOp = false
                    elseif (StringType.compare(args.stringType, StringType.REAL)) then
                        set val = S2R(op)
                        if (val &lt; 0) then
                            set operators[count] = &quot;+&quot;
                            set count = count + 1
                            set nums[count] = val
                        else
                            exitwhen true
                        endif
                    else
                        exitwhen true
                    endif
                endif
                set args = args.pop()
            endloop
            if (args != 0) then
                call args.destroy()
            endif
            
            if (processed) then
                set evaluation = nums[count]
                loop
                    exitwhen count == 0
                    set count = count - 1
                    if (operators[count] == &quot;+&quot;) then
                        set evaluation = evaluation + nums[count]
                    else
                        set evaluation = evaluation - nums[count]
                    endif
                endloop
            endif
            
            return processed
        endmethod
        
        private static method run takes player caller, integer callerId, string args returns nothing
            local real val
            set args = FilterString(args, &quot; &quot;, false)
            if (args == &quot;?&quot;) then
                call DisplayTextToPlayer(GetTriggerPlayer(), 0, 0, &quot;4 function calculator&quot;)
                call DisplayTextToPlayer(GetTriggerPlayer(), 0, 0, &quot;Just input an expression like 1+1-5&quot;)
            else
                if (eval(args)) then
                    set val = evaluation
                    
                    call DisplayTextToPlayer(caller, 0, 0, &quot;eval: &quot; + R2S(val))
                endif
            endif
        endmethod
        
        implement Shell
    endstruct
    //////////////////////////////////////////////////////////////////////////////////////////
    private function ini takes nothing returns nothing
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 90000, &quot;type - to get list of commands and # to get list of shells&quot;)
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 90000, &quot;type -command to run command, #-shell to change shell, and !- string to run shell&quot;)
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 90000, &quot;input ? into command or shell to get information about it, like -add ? or !- ?&quot;)
        call IniSubtract()
    endfunction
endscope
</i>
 

Attachments

  • test map.zip
    39.2 KB · Views: 223

tooltiperror

Super Moderator
Reaction score
231
How about a simpler demo code for those who don't feel like reading a wall of JASS? Also, why a struct interface? A function call would be so much nicer, or atleast some sort of (better) module.

Edit:
JASS:
call CMD_RegisterCommand(&quot;-give&quot;,&quot;-giveaway&quot;,2,function callback)
function RegisterCommand takes string command, string altcommand, integer argcount, code callback returns nothing
 

Nestharus

o-o
Reaction score
84
How about a simpler demo code for those who don't feel like reading a wall of JASS?

Wanted to display layered commands as well as evaluations =).

Also, why a struct interface? A function call would be so much nicer, or atleast some sort of (better) module.

Well, I think an OO design is actually better, but then again I'm a very OO kind of person. I can't really make the module different as the module implements a custom interface (like the interfaces in vjass).

Now, your alternative stuff here
[ljass]function RegisterCommand takes string command, string altcommand, integer argcount, code callback returns nothing[/ljass]

The stuff would actually be even more complicated as you'd have to write out stuff like this inside of your own function

[ljass]if (enabled and access[root.playerId]) then[/ljass]

I find the current layout to be the best possible way to do it while maintaining the current features ; |. Believe me, I put a lot of thought into it : P. If you can come up with an API simpler than this that retains all of the features, I'll be glad to change the whole design to that = ).

I also do plan to add MIN_ARG and MAX_ARG (max arg < 0 being infinite) to the system. An argcounnt does not do this system justice ; |. Of course, the checks would be done within the modules as the only thing you can check for in the core is whether or not the command exists (due to multiple instances of commands each with their own settings)
 

tooltiperror

Super Moderator
Reaction score
231
But I find the structs overkill, personally. I do not want to make a struct for every command, could you at least make it possible to use one global struct?
 

tooltiperror

Super Moderator
Reaction score
231
This is getting rather complicated. I was hoping for something like this.

JASS:
//! Note: Comment serves no purpose.
  private struct Data extends array
     command display
  
     private method display takes nothing returns nothing
         call BJDebugMsg(.arg[1])
           if .arg[2]!=null then
               debug call BJDebugMsg(&quot;You have entered two many arguments!&quot;)
           endif
     endmethod

     implement Cmd
  endstruct


Do you see what I mean? I want you to take all of the work out of command parsing for me and just spit back the arguments given by the player in an array called this.arg[], .arg for readability, then do assorted things like make sure to parse things between "quotes" as one argument. That's what I meant by coding in one struct. Then you could just keep adding members and methods with the same name, don't know if vJASS let's yu do that, but you could always use a textmacro interface if you have to (it all compiles to the same thing anyway).
 

Nestharus

o-o
Reaction score
84
1. Stack is more dynamic than an array, so it's more effective to use a stack than an array.

A global struct for a root command is impossible as each specific instance has its own settings.

Try this design = )
JASS:
private struct Display1 extends array
    public static constant string COMMAND_NAME = &quot;display&quot;
    public static constant boolean AUTO_ENABLE = true
    public static constant boolean AUTO_ACCESS = true
    public static constant integer MIN_ARGS = 1
    public static constant integer MAX_ARGS = 1

    private method display takes Args args returns nothing
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, args.value)
    endmethod

    implement Command
endstruct

private struct DisplayInt extends array
    private static delegate Display1 default = 0

    private static method display takes Args args returns nothing
        if (args.stringType == StringType.INTEGER) then
            call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, args.value)
        endif
    endmethod

    implement Command
endstruct

private struct DisplayReal extends array
    private static delegate Display1 default = 0

    private static method display takes Args args returns nothing
        if (StringType.compare(args.stringType, StringType.REAL)) then
            call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, args.value)
        endif
    endmethod


    implement Command
endstruct

private struct Display2 extends array
    private static delegate Display1 default = 0
    public static constant integer MIN_ARGS = 2
    public static constant integer MAX_ARGS = 2

    private method display takes Args args returns nothing
        call BJDebugMsg(args.value+args.next.value)
    endmethod

    implement Command
endstruct


Of course you could just have structs with default fields in them and no commands or anything and have your other structs implement them, like a struct for 2 args or one for 6 args or w/e ; ).

If you want high simplicity, don't care about evaluations, and don't care about specific access restrictions to specific command instances (root commands only), then I suggest Quraji's Command Parser.

This one was made to be a bit faster on the executions (about double speed?) and have a bit more power, but as you see, that stuff results in more complexity ; P.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top