|
Zugg |
Posted: Tue Jul 10, 2007 10:54 pm
Lua in CMUD v2.0 |
|
Thinjon100 Apprentice
Joined: 12 Jul 2004 Posts: 190 Location: Canada
|
Posted: Fri Jul 13, 2007 7:22 pm |
Just out of curiosity, Zugg... does this mean that since you've got Lua backreferencing the window that called a trigger, that you've made a similar change for zScript? I know from another thread that you'd mentioned updating/fixing %window and/or %curwin so that one (or both) returned the window that called a trigger.
|
|
_________________ If you're ever around Aardwolf, I'm that invisible guy you can never see. Wizi ftw! :) |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Fri Jul 13, 2007 8:16 pm |
Yes...and...Yes ;) In v2.0, %window will return the name window that received the text firing the trigger, and %curwin returns the name window with the current keyboard focus. Also, there are two two variables: %windowid returns the ID of the window that fired the trigger, and %curwinid returns the ID of the window with the current keyboard focus.
|
|
Last edited by Zugg on Fri Jul 13, 2007 8:17 pm; edited 1 time in total |
|
|
|
Thinjon100 Apprentice
Joined: 12 Jul 2004 Posts: 190 Location: Canada
|
Posted: Fri Jul 13, 2007 8:17 pm |
Whee! Thanks Zugg! :) *bounce*
|
|
_________________ If you're ever around Aardwolf, I'm that invisible guy you can never see. Wizi ftw! :) |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Fri Jul 13, 2007 8:20 pm |
Also, I should note that the window name is the name given in the settings editor for the window object itself. In past versions, %curwin returned the ID of the session (which didn't have much to do with the name of the window in CMUD). A new %sessionid returns the ID name of the session now.
|
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Fri Jul 13, 2007 10:35 pm |
OK, I've got to say that working with Lua is the most fun I have had in a *long* time. The Lua API is just fantastic! I haven't run into any bugs or problems...it just does what it is supposed to, quickly and easily. Fortunately, I got a copy of the "Lua Reference Manual" at the same time that I bought the "Programming in Lua" book. The reference manual has been a big help. I know it's all on the web, but there's nothing like having the book open next to you while you code (besides, I hope the Lua author is getting some money from these books).
I've been buried in UserData, MetaTables, UpValues, etc for a couple of days now. Today I got the "var" table within the window userdata working. My desired syntax was easy to implement. In fact, it almost worked the first time I tried it (and it was only a very minor bug that stopped it from working the first time).
I also found a great help in the Lua Wiki: Binding with Members and Methods. This set of example C code really helped in putting together my zsMudWindow userdata in a correct and extensible way. Once I got the hang of that, doing a zsVarType usertype for the zs.var table was a breeze. In fact, it had an interesting side effect...the zs.var really does act like a normal Lua table. You can even do this:
Code: |
vars = window["tells"].var
print( vars["myvarname"]) |
where "vars" now points to the table of all variables within the window "Tells".
The only thing I haven't figured out how to do yet is allow the table to be iterated with the "pairs" function. I had thought there would be a metatable method (similar to __index or __newindex) for doing iteration (like __next or something). But I haven't found anything like that yet. So I need to go read up on custom userdata iterators and see how that works.
But I just had to post and say how happy I was with how this is all working. I should have looked into Lua years ago! Thanks to everyone who helped push me in this direction. This is going to have a *huge* impact on CMUD. |
|
|
|
Tech GURU
Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Sat Jul 14, 2007 12:51 am |
This is all really cool stuff and I'm glad you're having a great time coding it because we'll have a great time using it.
Now if I can just figure what I can build with this. |
|
_________________ Asati di tempari! |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat Jul 14, 2007 1:12 am |
I was just thinking - we can use the var table of a zsMudWindow object to access variables in that window, but how can we access variables that aren't in windows? Is there a similar syntax for modules, or is the only way to use the (rather unwieldy) var["//module/class/var"] syntax?
|
|
|
|
Daagar Magician
Joined: 25 Oct 2000 Posts: 461 Location: USA
|
Posted: Sat Jul 14, 2007 2:59 am |
One of the most exciting things is seeing you yourself get excited about it Zugg. I can only imaging the patience required to work on essentially the 'same' project for years and years on end - finding new ways to keep it interesting means we all win. I'm with Tech though... all this amazing power coming, and I need to find something to use it on....
|
|
|
|
Nick Gammon Adept
Joined: 08 Jan 2001 Posts: 255 Location: Australia
|
Posted: Sat Jul 14, 2007 6:18 am |
Zugg wrote: |
The only thing I haven't figured out how to do yet is allow the table to be iterated with the "pairs" function. I had thought there would be a metatable method (similar to __index or __newindex) for doing iteration (like __next or something). But I haven't found anything like that yet. So I need to go read up on custom userdata iterators and see how that works.
|
I think the quick answer is that you won't make pairs do it directly, but you can write your own iterator that will (zpairs, for instance). If you read up on writing iterators that should give you some good ideas.
Effectively you can make an iterator that works inside a 'for' loop do anything you want. For example, I wrote one a while back that iterates over a string and breaks it into lines at a delimiter.
I am glad you are enjoying Lua. It certainly is good to work with - a nice clear API that is designed to be easy to interface with, compared to certain other languages on the market. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Sun Jul 15, 2007 6:58 pm |
OK, I thought of something that I've forgotten to include in my design:
How to execute CMUD aliases and user-defined functions from within a Lua script? In zScript, you can just call an alias directly by name. You call a user-defined function via @funcname(args). But the "zs" object already calls the built-in zScript commands and functions. So if you have an alias name that is the same as a command or function, then "zs.aliasname" isn't going to work. Same problem for user functions.
It needs to be something else within the "zs" object (since that is the window object itself). The "zs.alias.aliasname" syntax already returns the alias object...it doesn't execute it. So we need something else to execute an alias. The syntax:
zs.exec("aliasname")
will already work just fine, but that's an inefficient call to the CMUD #EXEC command. I'd like something more direct that doesn't use the existing CMUD commands. Maybe something like this:
Code: |
zs.a.aliasname(args)
x = zs.f.functionname(args) |
??
I don't know...seems a bit kludgy to me. Any ideas?
Quote: |
but how can we access variables that aren't in windows? |
I'm considering having a "modules" table that works similar to the "windows" table, but contains all of the modules. Or maybe I'll just put the modules into the existing "windows" table itself and then add a property to determine if a zsMUDWindow object is a module or window (something like zs.iswindow). Internally, a CMUD module and window are the same thing, except that the module doesn't have the user interface object. So doing "module.echo" isn't going to make any sense.
Quote: |
but you can write your own iterator that will (zpairs, for instance). |
Thanks for that tip Nick. I'll look into iterators and see what I can come up with. And yes, other scripting designers (even myself) could learn a lot from the clean Lua API. What I'm really excited about is having our new TeSSH client (SSH without the MUD specific stuff) with Lua support could be a big selling point for sysadmins. Having a business-based Telnet/SSH client with Lua scripting is a lot more interesting, in my opinion, than an SSH client using zScript (with all of the MUD-related stuff that's part of it). I can easily see making Lua the default scripting language in the public version of TeSSH. |
|
|
|
Tech GURU
Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Sun Jul 15, 2007 8:17 pm |
I think making Lua the default language of TeSSH is a great idea. It's a great way to distance it from what stigma there may be to it's MUD roots.
As for access user function and commands how about something like
Code: |
zs.custom("lootCorpse");
y = zs.custom("calcGold", 300, 5); |
That is to to say zs.custom will access either by name with additional or an array parameter being pass to the function or alias.
If you need disambiguation then something like
Code: |
y = zs.custom.a("getGold", "corpse");
z = zs.custom.f("getGold", "bank", 300, 0.05); |
Should do the trick. |
|
_________________ Asati di tempari! |
|
|
|
Nick Gammon Adept
Joined: 08 Jan 2001 Posts: 255 Location: Australia
|
Posted: Mon Jul 16, 2007 12:10 am |
What I did (and this applied to all scripting languages) was to simply have a function world.Execute ("some string") that simply sent the string back to the command parser. Thus aliases, speedwalks etc. could be evaluated.
This is pretty-much what Tech is suggesting with zs.custom. I'm not sure why you need to separate out the arguments. Assuming you have an alias "calcGold" that expects a couple of numbers, why not just do:
Code: |
zs.custom("calcGold 300 5")
|
|
|
|
|
Tech GURU
Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Mon Jul 16, 2007 2:30 am |
That can be done as well but then you need single quotes for parameters that were multiple spaces. It's not really an issue for aliases but what about functions?
Consider a that had two parameters. One of the things I plan to turn into a function (I have a pseudo-funtion based on aliases) converts money represented a string to denominations of a particular unit.
Code: |
zs.custom("convertGold", "3 ebony Marks and 1 copper bit", "Crescent") |
I know in this case I could easily reorder my parameters, but I think the points gets across. I suppose it's a matter of preference since
Code: |
zs.custom("convertGold '3 ebony Marks and 1 copper bit' Crescent") |
isn't that different either, but I think the way I suggested reads better. |
|
_________________ Asati di tempari! |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Jul 16, 2007 2:42 am |
Nick: As I mentioned above, there is already a zs.exec("some string") command. That's the way Lua calls the normal CMUD #EXEC command. That works fine, but it would be more efficient to come up with another syntax since calling the main command parser introduces a lot of unneeded overhead when you just want to execute an alias. By allowing Lua to parse the arguments (300 and 5 in your example above), you gain more speed over just passing them to the command parser. And it's trivial to grab the arguments from the Lua command line, so I'd rather let Lua parse them.
In other words, you can already do this:
Code: |
zs.exec("calcGold 300 5") |
but I want something additional like this:
Code: |
zs.execalias("calcGold", 300, 5) |
which would be faster and would handle arguments better. It would also allow you to pass a Lua table to an alias, and CMUD is converting tables to/from string lists or database variables in CMUD, so it can be pretty powerful.
Maybe I'll just use zs.execalias and zs.execfunc ?? |
|
|
|
bortaS Magician
Joined: 10 Oct 2000 Posts: 320 Location: Springville, UT
|
Posted: Mon Jul 16, 2007 5:12 am |
Zugg wrote: |
Maybe I'll just use zs.execalias and zs.execfunc ?? |
I think this is a good idea, since it tells me exactly what's going on. The previous syntax is too ambigous and could cause a bunch of confusion for new users. With those two, there is not question as to what is intented. |
|
_________________ bortaS
~~ Crusty Klingon Programmer ~~ |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Jul 24, 2007 1:20 am |
Well, I've run into some glitches with Lua. Seems it doesn't like being called from other threads sometimes. Most of the time it works just fine. The other thread calls the lua_newthread function and then executes a script within that new thread state. But sometimes if I spam the same Lua Alias over and over again really quickly, I get Lua all locked up.
I've tried using critical sections and that didn't help. I also tried using the Delphi Synchronize command to execute the Lua script within the main thread, and that didn't help either. So I'm not exactly sure what is happening here. It feels like a thread locking issue, but as far as I can tell, only one thread is executing at a time. This could take a while to figure out :( |
|
|
|
Nick Gammon Adept
Joined: 08 Jan 2001 Posts: 255 Location: Australia
|
Posted: Tue Jul 24, 2007 3:00 am |
Have you read: http://lua-users.org/wiki/ThreadsTutorial
I haven't used threads personally (I use co-routines) however it looks like you should be implementing lua_lock and lua_unlock.
The post above shows how you might implement such routines with critical sections. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Jul 24, 2007 4:24 pm |
Looks like lua_lock and lua_unlock are part of the Lua implementation itself, and not the user application code? Wouldn't the Windows version of Lua.DLL already implement these routines using Windows critical sections? I haven't done much with looking at the raw Lua source code, and I don't really have any C environment that I can use to rebuild it. Also, I had hoped that CMUD could just use the standard Windows Lua DLL distribution, and not require a "special" version.
Or are these routines added via the C API? The article you mentioned seems to talk more about changes to the Lua source code, rather than how one would implement this in an embedded application. |
|
|
|
Rorso Wizard
Joined: 14 Oct 2000 Posts: 1368
|
Posted: Tue Jul 24, 2007 6:03 pm |
Zugg wrote: |
I don't really have any C environment that I can use to rebuild it.
|
I recommend Visual C++ Express. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Jul 24, 2007 7:00 pm |
Thanks Rorso, I'll take a look at that if I need it. Although my point was that I don't really *want* to rebuild Lua. I'd like CMUD to use the standard DLL distribution.
Anyway, it looks like my problem is completely different than I thought. It doesn't have anything to do with threads or locking at this point...even if I just execute an alias slowly, it hangs after the 34th attempt. So it looks more like I'm not cleaning the Lua stack up properly somewhere, and it's leaving something behind, and this eventually exceeds the Lua stack size, and causes the crash. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Jul 24, 2007 7:29 pm |
Yep, that was it. When you create a new thread in Lua, you do this:
NewState = lua_newthread( MainState)
this pushes the new thread object onto the MAIN stack. Well, in my cleanup routine, I was doing this:
lua_pop( NewState, 1)
This was wrong. I was supposed to be doing this:
lua_pop( MainState, 1)
to remove the thread from the MAIN stack. Once I fixed this, then it works fine now, and I'm not seeing any thread issues so far. Glad it was fairly simple to find, even though I got sidetracked on the wrong idea. |
|
|
|
Nick Gammon Adept
Joined: 08 Jan 2001 Posts: 255 Location: Australia
|
Posted: Wed Jul 25, 2007 1:02 am |
I completely agree with your idea of using standard Lua. However if you did need to rebuild it, downloading Cygwin lets you compile it quickly.
Judging by a re-read of the post on threads, Lua should internally handle its concurrency issues OK, but those callouts were provided in case some other resource of yours also needed locking.
I actually supply a slightly different Lua 5.1 DLL with MUSHclient, as described here:
http://www.gammon.com.au/forum/?id=7795
The main reason for the changes are to turn off the "compatability" options, for backwards compatability with Lua 5.0. Your users would hardly need those, and it is probably a good idea to discourage the use of constructs that are likely to be removed in future version.
Also you can use 64-bit longs for one of the format conversions, which gives a bigger range of numbers that can be converted.
However the changes are so minor that you could swap in a standard Lua 5.1 DLL if you wanted to. |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat Aug 04, 2007 11:24 am |
I know it's a stupid example, but I'm curious. Would this work as intended?
zs.cmd.say("You have @gold gold left")
or maybe even
zs.cmd.say("The string is member number %ismember("..string..",@stuff).") |
|
|
|
Larkin Wizard
Joined: 25 Mar 2003 Posts: 1113 Location: USA
|
Posted: Sat Aug 04, 2007 12:35 pm |
I'm betting that the variables won't be expanded in commands like this because they're quoted. It's a good question, though, to clarify the Lua quoting versus the CMUD quoting...
|
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Aug 06, 2007 6:25 pm |
Doing:
zs.cmd.say("You have @gold gold left")
is exactly the same as doing:
#say "You have @gold gold left"
and since @gold is within quotes, it doesn't get expanded. Remember that CMUD scripts are compiled, so what you need is someway to bypass the compiler, which is what the #EXEC command is for. So you can do this:
zs.exec("#say You have @gold left")
(which is the same as zs.cmd.exec btw). Or, you can use Lua itself to create the proper argument, like this:
zs.say("You have " .. zs.var.gold .. " left")
which would be the more Lua-like way of doing it. |
|
|
|
|
|