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
top