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, confirm your email, resolve issues, 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.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ SMAUG ➜ Lua ➜ wait.lua

wait.lua

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


Pages: 1  2 

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #15 on Mon 21 Jan 2008 10:31 AM (UTC)
Message
Quote:
I haven't looked into luaSockets yet, but have heard of too many stability issues.

I'd be curious to hear about this, since in my experience it's been quite stable. Then again, I haven't built a whole server around it, and chances are that I will use C/C++ for the networking anyhow. (The reason is that I want to control the packets myself since it matters. The point just in this case is not to have an "easy API".)

Quote:
In the stock SmaugFUSS the fence is currently well defined. Anything used on the C side should remain on the C side. If you move enough functions to Lua then eventually the C variables can move to Lua as well.

Well, that's certainly how it is, but I guess I was wondering about how things should be. For instance, is the 'ideal situation' one where everything but networking is handled in Lua? One where the 'core concepts' are in C and Lua is for everything else? One where the MUD engine variables are in C but game-specific variables in Lua? One where C implements a driver and Lua acts as LPC? (In that case, Lua is basically doing all the interesting work with C providing the underlying architecture.)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Darwin   USA  (125 posts)  Bio
Date Reply #16 on Tue 22 Jan 2008 03:37 AM (UTC)

Amended on Tue 22 Jan 2008 08:01 AM (UTC) by Darwin

Message
Can you think of a way to automatically have the task functions (accept, abort, complete, etc.) wrapped by the wait.make() function? I have tried a few things that have not resulted in anything good. For instance, I tried wrapping the functions from within the for loop at the end of the tasks.lua file. That resulted in each of those functions being executed immediatly after being wrapped, and (now) I understand why that happened.

Could there possibly be a way to wrap those functions using a metatable? I haven't gotten too familiar with metatables as of yet, so I'm not certain how they function.
Top

Posted by ThomasWatts   USA  (66 posts)  Bio
Date Reply #17 on Tue 22 Jan 2008 06:46 AM (UTC)
Message
Coroutines can not in standard Lua yield properly inside a for loop. More information here:
http://lua-users.org/wiki/YieldableForLoops
http://lua-users.org/wiki/LuaPowerPatches

Good metatable information is available here:
http://pgl.yoyo.org/luai/i/2.8+Metatables
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #18 on Tue 22 Jan 2008 09:24 AM (UTC)
Message
Quote:

Can you think of a way to automatically have the task functions (accept, abort, complete, etc.) wrapped by the wait.make() function?


I'm not sure I would want to do that, for the reason that the task system calls functions like accept which are expected to return a value (eg. "Return false if task can not be accepted"). Now if you make it into a coroutine then the decision to return true or false might be deferred, which is not what the rest of the task system expects.

As an analogy, say a teenager asks his Dad "can I have the keys to your car, I want to take my girlfriend out tonight", and his Dad replies "I'll tell you tomorrow or the next day", that wouldn't be a satisfactory response. You would reply "I need to know now, not tomorrow".

Quote:

Could there possibly be a way to wrap those functions using a metatable?


I don't know what you mean by this. Metatables apply to tables, you don't wrap functions in them.

Quote:

Coroutines can not in standard Lua yield properly inside a for loop. More information here:
http://lua-users.org/wiki/YieldableForLoops


The examples there seem to suggest that iterator functions don't work if you yield in the middle, however my tests show that repeat ... until with a yield in the middle work OK. For example:


repeat
  < ask some question >
  < await a response (yield) >
until <a good reply>


This seems to work fine.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #19 on Tue 22 Jan 2008 09:51 AM (UTC)
Message
Iteration is semantically equivalent to recursion anyway, so you can replace a loop with an anonymous function that has the same effect.
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #20 on Tue 22 Jan 2008 11:29 AM (UTC)
Message
Quote:
Coroutines can not in standard Lua yield properly inside a for loop.

To clarify, it's not that coroutines cannot yield in the context of a for loop, it's specifically the iterator function that cannot yield.

Quote:
Iteration is semantically equivalent to recursion anyway

A minor quibble... Although I see what you mean and agree, the "semantically equivalent" bit seems like a bit of a misnomer... or perhaps we are not using the word 'semantics' the same way. I would say (and this is how the theory of prog. lang. books I've read say it) that iteration and recursion are in fact very different semantically because they do very different things. I'd be more comfortable saying that they can express the same things in the end of the day. (Where "things" is intentionally left vague for now. It would take too long to define how exactly they are equivalent...)

Basically semantics, I have been led to believe, means precisely the effect of a language construct upon program state or flow. In that sense iteration and recursion are doing different things. It's like in logic; the semantics of a language is how you find values for sentences based on interpretations, whereas the expressiveness of a language is what differentiations you may make (or perhaps more accurately which classes of models you may distinguish from others).

Well, enough...

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Isthiriel   (113 posts)  Bio
Date Reply #21 on Tue 22 Jan 2008 12:58 PM (UTC)
Message
I meant that, given a function f() that performs some specific operation, it is impossible to tell whether it uses iteration or recursion to acheive that operation without reading the code involved.

That is, in pseudocode:
def f1():
   i = N
   while i > 0:
      i -= 1
      g()

And:
def f2():
   def h(i):
      if i > 0:
         g()
         h(i - 1)
   h(N)

Are indistinguishable, they perform the same operation, they have the same meaning, calling f1() is semantically equivalent to calling f2(). (Modulo OOB effects like a stack overflow or memory exhaustion because you recurse too deeply.)
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #22 on Tue 22 Jan 2008 02:02 PM (UTC)
Message
Right. I'd have said that the function effects are semantically equivalent, not the concepts of iteration and recursion. The functions are quite simply doing different things to the program state as they work, even though in the end after executing the entirety of both functions you end up with the same program state. Perhaps, as I said, we're simply using different meanings of the word 'semantics'.

(Hmm... what are the semantics of 'semantics'? *groan*)

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 #23 on Tue 22 Jan 2008 09:44 PM (UTC)
Message
Quote:

(Hmm... what are the semantics of 'semantics'? *groan*)

Depends on how you define 'are'.(dems jokes)

Quote:

Metatables apply to tables, you don't wrap functions in them.

From Lua you can only set metatables to other tables. From C you can set individual metatables to tables and userdata, otherwise it's system-wide metatables to other data types(ie. strings).
The relevant code is in 'lapi.c' in the standard Lua distribution.
So really you could wrap a function with a metatable, but I'm not really sure what the point would be. You could obfuscate through the '__call' mechanism for needless complexity.
Perhaps using the '__call' meta method the functions could be wrapped to auto resume the related coroutine. That would make coroutines transparent to the non-lib writing developers.
Top

Posted by Kline   (2 posts)  Bio
Date Reply #24 on Thu 30 Jul 2009 12:48 AM (UTC)
Message
Hello, so, I apologize for the horrible thread necro, but this is something I've recently tried to implement in my own base taking most of my implementation from Nick's work on Smaug, adding some things, and fitting it to my code.

At this point I have characters (NPC/PC), objects, and rooms all able to initialize and run their own state -- works great. However, following the wait.lua implementation through this thread I can only seem to have characters work successfully.

When I attempt to add a delay on objects in a script it simply doesn't process, it acts like it doesn't exist. When I try the same on a room, it somehow swaps the memory pointer of the room to that of me, and I'm not sure how.

I figured this would be the best place to start with any tips on tracking this down, as I'm just banging my head against it for now :(.
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #25 on Thu 30 Jul 2009 07:44 AM (UTC)
Message
It is almost impossible to debug a problem in a script, in code you have changed in Smaug, without seeing the script or the code.

All I can suggest with such little information to go on is gdb, put breakpoints in and see if what you think should happen, is happening.

http://mushclient.com/gdb

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Kline   (2 posts)  Bio
Date Reply #26 on Thu 30 Jul 2009 01:54 PM (UTC)
Message
Well I'm not running Smaug for starts, but rather borrowed the implementation of some things from it (like your Lua setup).

I know how to use GDB, and am aware you can't be expected to debug anything without code or script -- I was hoping for a little more insight of what might be useful to see, but since that didn't happen, I'll just throw something out there and hope for the best :)

Test script being executed on a room, with luaL_dofile()

rsend("Obj 1")
rsend("Obj 2")

local room = mud.room_info()
rsend(room.name)


Output:
Quote:
Obj 1
Obj 2
The Armory


Memory locations for pointers in my list of Lua elements. ptr->owner is a void* that is cast to the appropriate type based on ptr->type. Type 3 is the room, type 1 is myself.
Quote:
[ DEBUG] ptr: 0x8b8adb0 ptr->type: 3 ptr->L: 0x8b8adc0 ptr->owner: 0x8b8acb0
[ DEBUG] ptr: 0x8b687b8 ptr->type: 1 ptr->L: 0x8bc32b8 ptr->owner: 0x8bc2d00


Now, I am using the wait.lua from the 1st page of this thread (the one Nick cleaned up some), with this test code:
wait.make( function ()
 rsend("In wait")
 wait.pause(3)
 rsend("Three seconds!")
 end
)


And here's the GDB when it explodes, with my type 3 (room) pointer somehow now pointing to myself.
Quote:
344 case LUA_TYPE_RM:
345 {
346 rm = static_cast<ROOM_INDEX_DATA *>(lua->owner);
347 if( rm->lua->L == L )
348 {
349 lua_pushstring(L,ROOM_STATE);
350 lua_gettable(L,LUA_ENVIRONINDEX);
351 lua_pop(L,1);
352 return rm;

(gdb) print rm
$1 = (ROOM_INDEX_DATA *) 0x8bc2d00
(gdb) print *(CHAR_DATA *)rm
<snip> name = 0xb778a3d4 "Kline"


Hopefully this is a good enough starting point? Full source for everything is available via public svn/WebSVN if anybody is truly interested in helping me work this since it's not a Smaug base, but is using most of the same Lua code.
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #27 on Thu 30 Jul 2009 09:03 PM (UTC)
Message
Hmm- so it works without the wait, right? Now if you add the wait, and do this:


wait.make( function ()
 rsend("In wait")
 wait.pause(3)
 rsend("Three seconds!")
 end
)


What happens exactly? The room name prints instead of "Three seconds"? It isn't totally clear what the problem is.

Let's step back and think how the wait works. Basically the script is running normally until you hit it. Then to implement waiting it has to:


  • Add a timer to a queue of timers - the timer must have in it some identifying information about the appropriate Lua thread (like the coroutine address)

  • Call coroutine.yield () to yield execution

  • Now the main C++ code resumes execution (after the call to the Lua script)

  • A second or so later the timer fires

  • The timer that we used in the first step is located in our queue

  • From that timer we find the correct coroutine address

  • The script is resumed doing a coroutine.resume (thread)


Now various things could go wrong here. For a start, is the correct coroutine being resumed? A simple display (like you seem to have, namely rsend("Three seconds!") ) would show we are back in it.

If nothing happens, maybe the timer never fires, or the wrong coroutine is resumed.

Next, I would be cautious about pointers. Any pointer found before the wait might have been freed and re-used by something else. So if you are getting some userdata (eg. to hold the room), then doing a wait, and then using it to display the room name, that pointer might be "old". I wouldn't store userdata over wait boundaries.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
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.


90,240 views.

This is page 2, subject is 2 pages long:  [Previous page]  1  2 

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.