Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ SMAUG ➜ Lua ➜ Routing interpret() through Lua first?

Routing interpret() through Lua first?

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Darwin   USA  (125 posts)  Bio
Date Tue 29 Jan 2008 03:21 AM (UTC)
Message
I've seen mention of a few people saying they've routed their interpret function through Lua first to see if there is a Lua command/function to take care of it. I'm curious as to how you go about doing that. Some pointers or an example would be helpful.
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #1 on Tue 29 Jan 2008 04:15 AM (UTC)
Message
Here's what I do:

Step 1: get a line from the network

Step 2: send it to Lua line handler
- check for coroutine to resume etc., if none, go to step 3

Step 3: send to C interpret
- before doing normal thing, send to Lua command handler; if that returns true, stop. If it returns false, do the normal interpret thing.

On the Lua side, I have a data structure that stores commands, that are just functions like C commands. If the command isn't in the structure, the Lua command handler returns false. If it is, then it considers the command handled even if the syntax etc. has an error in it.



My command handler looks like this:


function _M.interpret(actor, cmd, ...)

    -- First, check to see that we actually have the command.
    local c = findCommandByPrefix(actor, cmd, CMD_PREFIX_LIMIT)

    if type(c) == "boolean" then
        return c
    end

    -- Check for permission.
    if c.checks then
        for _, check in ipairs(c.checks) do
            local ok, whynot = check(actor)
            if not ok then
                actor:sendText("You can't do that: ", whynot, "\n")
                return true -- we 'handled' the command.
            end
        end
    end

    -- ok, run the command.
    local co = coroutine.create(c.code)
    local result = { coroutine.resume(co, actor, ...) }

    -- first value is true/false; false if errors.
    -- if false, then result[2] is error message.
    if not result[1] then
        actor:sendText("There was an error executing the command.\n")
        actor:sendText("Please be sure to tell an admin about this.\n")
        error(result[2])
    end

    -- Deal with however the command terminated. E.g. we might
    -- need to reschedule the command.
    return handleCommandResult(actor, c, co, result)

end


The data structure I use is a lexical trie, in case that makes a difference.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by ThomasWatts   USA  (66 posts)  Bio
Date Reply #2 on Tue 29 Jan 2008 06:32 AM (UTC)
Message
My personal butchery as follows:
interpret.c: Extra check before calling do_fun, between timer checks.

	/* check for command in character then mud lua first */
	if( call_lua(ch, cmd->fun_name, argument, NULL) == LUA_NOT_FOUND )
		(*cmd->do_fun) ( ch, argument );


Lua Code example: the command is of course, echo

-- attempt at dynamic (overwritting internal) function
-- it exists already in C, act_wiz.c
function do_echo(ch, argument)
	mud.msg_game("do_echo lua override: " .. argument, color.immort)
end


There is of course slightly more to the trick than the above, such as func name lookup which requires dynamic lookup (already in SmaugFUSS). My call_lua may be different from the stock one, I really don't remember.
As always, Your Mileage May Vary
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #3 on Tue 29 Jan 2008 11:00 AM (UTC)
Message
That reminds me: by the time Lua gets the arguments, they've been divided into a list according to the standard parsing rules. (I don't use an 'argument' string, I use varargs to pass in the arguments one at a time.)


Here's my echo example:


makeCommand {
    name = "luaecho",

    usage = "[stuff to echo]",

    brief = [[Echo a string to stdout.]],

    code = function(actor, ...)
        for i = 1, select('#', ...) do
            actor:sendText(i, ":", select(i, ...),
                " (len:", #select(i,...),")\r\n")
                actor:sendText("\n")
        end
    end,

    --checks = {cmdchks.isPc, cmdchks.isImmortal, },
}


There's a bit more stuff going on because here you see the creation of the whole command structure, not just the command function. The name/usage/brief stuff lets you document commands where the command code is. I'm going to have to experiment with whether or not this is a good idea, and how to override settings set by the code.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


15,760 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.