Register to post in forums, or Log in to your existing account
 

Play RetroMUD
Post new topic  Reply to topic     Home » Forums » CMUD Beta Forum
Merzbow
Beginner


Joined: 02 Sep 2006
Posts: 10

PostPosted: Tue Sep 05, 2006 10:31 pm   

why the #WAIT hate?
 
I don't understand the animosity towards #WAIT. From what I gather from Zugg's article the problems with this come about when #WAIT is used in triggers. I don't use #WAIT in triggers. I use it in scripts that wait in loops for something to happen, then proceed. I find this very easy to reason about and code for, so why take this ability away?

For example, in my MUD, many actions come with an associated variable roundtime. So I wrote a script like this called "wfr" (wait for roundtime) - (and yes this is pseudocode):

wfr
{
set temp trigger that fires on RT string and sets RT variable
set RT variable to 0
until RT variable is set
{
#wait 200
}
#wait for number of seconds in RT variable
}


Then I can easily write scripts like this:

remove weapon
wfr
climb hill
wfr
wield weapon
wfr

I've created variations of wfr that do stuff like wait on multiple strings and return which matched, and so on. They all have timeouts or are easily cancellable by me with ESC. For example, I have wfmr, which takes a variable name and a bunch of match strings, waits for a match, and returns the index of the string that matched. It also waits for a roundtime after the match. I can use it like this (to make up a contrived example) - (and yes this is also pseudocode):

killorc
{
set orcdead to 0
until orcdead is greater than 0
{
attack orc
wfmr result "You kill the orc" "You hit the orc" "You drop your sword"
case result {orcdead=1} {} {get sword; wfr}
}
}

It seems that Zugg's scripting philosophy is event-driven to a fault. I think it is far easier to write and reason about scripts written in a functional manner, instead of breaking up the script into many pieces that hang off of individual triggers and alarms. I'm hiding tons of complexity within function calls as you can see above. I despair of writing a script like that with just triggers and alarms that's remotely as simple.

To see how easy MUD scripting should be, consider any of the StormFront/Wizard scripts that are made for Simutronics games. They are all functional; you can output commands to the game, then call 'match' or 'matchwait' to wait for a specific MUD response (and that handle roundtimes transparently), then continue, then match again, and so on.

So far I've been able to get away with doing things this way in ZMud because of #WAIT. I don't see any technical reason why this paradigm should be discouraged, given that I avoid all the pitfalls mentioned in Zugg's article by not waiting in triggers. Triggers are cool and have their uses, but I've always found sequential scripting far more useful and natural in a MUD. If this ability is going to be taken away in cMUD, please let me know now so I can consider my options.
Reply with quote
Zugg
MASTER


Joined: 25 Sep 2000
Posts: 23379
Location: Colorado, USA

PostPosted: Tue Sep 05, 2006 10:58 pm   
 
This really belongs in the zMUD forum. But zMUD/CMUD is "event driven" because that's how Windows works. Windows is completely event-driven, as is the network system.

The problem with using #WAIT is that it's not clear what you should wait for. How much of the program should stop? Should the mouse and keyboard activity stop? Clearly not. The mouse and keyboard are "event driven" in Windows, and you expect them to continue to respond. Well guess what...the network input/output is also event driven in Windows. So while your script is "waiting", you want all MUD input to stop (but probably not MUD output). So then what about other triggers? What if the stuff you are waiting for never comes? Do you just hang forever?

The way #WAIT is implemented in zMUD is that a new message thread is created. This allows Windows to continue processing other messages, like for the keyboard and mouse. During the delay, MUD input and output is also accepted and other triggers can fire on the incoming text.

So, imagine that you have a trigger that fires on common text that does a #WAIT 1000 (10 seconds). You can end up with more and more threads as more wait commands are executed and put into the background.

Waiting in an alias has the same problems as waiting in a trigger...the article just focuses on triggers, but the same problems explained in the article exist no matter where you use Wait.

Using Wait is actually a lot like old-style programming using "go-to" rather than using structure programming. While it takes some getting used to, event-driven languages perform and scale much better than "wait-style" programming.

And no, neither zMUD nor CMUD are ever going to change to the limited capabilties of the StormFront/Wizard clients. I'm sure there are plenty of zMUD/CMUD users here that can give you an earful why you shouldn't be coding scripts like that and why the zMUD event-driven model is better.

#WAIT still exists in CMUD, but it still has the same problems and limitations as with zMUD and is not recommended for general use. If you want to use it, then fine, I don't care. You might find it more "natural", but you are missing out on a lot of performance and improvements by rejecting the event-driven model.
Reply with quote
Merzbow
Beginner


Joined: 02 Sep 2006
Posts: 10

PostPosted: Wed Sep 06, 2006 12:04 am   
 
I'll ask in the main ZMud forum for examples of how scripts like the ones I have above can be implemented in ZMud in a way that is easy to understand. I understand how simple scripts can be converted to multi-case triggers, but the paradigm breaks down for me once you start getting into complications like nested loops, reuse of multiple-matching code, etc.
Reply with quote
Merzbow
Beginner


Joined: 02 Sep 2006
Posts: 10

PostPosted: Wed Sep 06, 2006 12:09 am   
 
An option would be to go whole-hog and add multithreading (I think this was mentioned as a possibility in an earlier thread). Give us synchronization primitives and the ability to execute scripts in separate threads. For the non-power-users you can formalize the atomic script changes you're talking about to stop ordinary users from shooting themselves in the foot with #PRIORITY and #WAIT. For power users it's completely up to us to make sure our threads synchronize properly.
Reply with quote
Namsar
Beginner


Joined: 14 Jun 2006
Posts: 29
Location: Sydney - Australia

PostPosted: Wed Sep 06, 2006 4:10 am   
 
I've always used #WAIT in my scripts cause quite honeslty I haven't found a better way to do things.

e.g. See a repop, wait 20 seconds, disconnect. wait 120 seconds.. reconnect.

How on earth can you code that event driven ?

Or another example.

I have triggers for attacking known mobs in an area based off the long description.
Some mobs I wish to intentionally attack last, so in their triggers I #wait 50 so that their attacks are delayed by that ammount.

I guess I don't see how else to do time based things without wait. ?
Reply with quote
Rorso
Wizard


Joined: 14 Oct 2000
Posts: 1368

PostPosted: Wed Sep 06, 2006 4:51 am   
 
Example on how to do the repop:
#alias repop {
#alarm +20 {
#echo disconnect
#alarm +40 {#echo reconnect}
}
}

You can do pretty much the same thing with the mobs:
#TRIGGER {({@mobs})} {#alarm +50 {kill %1}}

Unfortunately the last example doesn't work in cMUD because of the new way arguments are expanded.
Reply with quote
Namsar
Beginner


Joined: 14 Jun 2006
Posts: 29
Location: Sydney - Australia

PostPosted: Wed Sep 06, 2006 5:26 am   
 
So what exactly is the difference between setting alarms, and just freezing the operation of one single trigger/alias with wait, they achieve almost exactly the same purpose, but from what I can see you have more problems with alarms when you try and put in multiple delays in a row.

e.g.
#BEEP
#WAIT 100
#BEEP
#WAIT 100
#BEEP
#WAIT 100
#BEEP
#WAIT 100
#BEEP
#WAIT 100
#BEEP


etc would end up with 5 nested alarms to achieve the same thing ?
Reply with quote
Rorso
Wizard


Joined: 14 Oct 2000
Posts: 1368

PostPosted: Wed Sep 06, 2006 5:51 am   
 
Namsar wrote:

etc would end up with 5 nested alarms to achieve the same thing ?

If you want to use the most general way of translating the scripts, yes. Otherwise you could do;

#ALIAS beep {beeps = %eval( @beeps+10)}
#VAR beeps {0}
#ALARM {10} {
#if (@beeps > 0) {
#beep
#echo beep
beeps = %eval( @beeps-1)
}
}
Reply with quote
Merzbow
Beginner


Joined: 02 Sep 2006
Posts: 10

PostPosted: Wed Sep 06, 2006 7:36 am   
 
Unfortunately the bottom line is that it is just much harder to write scripts in this way, even though they may theoretically be more powerful. Trying to write a script that needs to wait on 4 different types roundtime in 20 places in 3 nested loops that branch to different places based on 5 different matches is fantastically complex if done solely in an event-driven manner, but is so easy in Wizard script that 12-year olds can write it. It would be far easier from my point of view to give me true multithreading, and let me code scripts and triggers the way I want and leave it up to me to manage my own synchronization instead of forcing me into a 100% event-driven paradigm.
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Wed Sep 06, 2006 10:57 am   
 
The short way...
#TRIGGER "RT1A" {-30} {#EXEC {%pop(RT1Queue)};#T- RT1A} {} {alarm|disable}
#TRIGGER "RT1" {Round time 1:(%d)({.%d|})} {#T+ RT1A;#CALL %alarm(RT1A,%eval(%1*1000+%2*100))}
#VAR RT1Queue {} {}
Duplicate that changing the names around for all 4 round times, then all your scripts need to do is dump commands in the right queue and check that your not waiting on that round time to decide whether to send 1 command.
#ADDITEM RT1Queue {remove weapon}
#ADDITEM RT1Queue {climb hill}
#ADDITEM RT1Queue {wield weapon}
#IF (%trigger(RT1A)=0) {#EXEC %pop(RT1Queue)}

Completely simple to my way of thinking. Of course this how the brain naturally works when issuing the commands manually. If some event occurs that takes precedence over the already thought out actions, meaning what is queued up, then the queue can be dumped and a new set of actions put in. Again script and brain function match.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Larkin
Wizard


Joined: 25 Mar 2003
Posts: 1113
Location: USA

PostPosted: Wed Sep 06, 2006 11:57 am   
 
I agree with Zugg and Vijilante on this. As a software engineer, I would avoid anything akin to a "goto" statement, such as the #WAIT command. It is inefficient and drains your resources, not to mention that it is much less flexible when you want to make changes to your script.

I disagree that adding "true multi-threading" capabilities to CMUD would be a good idea. As someone who has written many multi-threaded applications on Windows and Linux, I know that it's truly painful to get all the synchronization just right. It would be many times harder to get it right when relying on a somewhat unknown software architecture that provides you an interface to its own threads.

The examples posted by Rorso and Vijilante are efficient and flexible. You can have any number of beeps you want. You can queue up as many actions as you want or even modify the actions on the fly based on other events that occur, such as dropping your sword instead of attacking successfully. It's just a different way of thinking for some of you, and that's going to take some adjustment.
Reply with quote
Dumas
Enchanter


Joined: 11 Feb 2003
Posts: 511
Location: USA

PostPosted: Wed Sep 06, 2006 12:05 pm   
 
Merzbow wrote:
Unfortunately the bottom line is that it is just much harder to write scripts in this way, even though they may theoretically be more powerful. Trying to write a script that needs to wait on 4 different types roundtime in 20 places in 3 nested loops that branch to different places based on 5 different matches is fantastically complex if done solely in an event-driven manner, but is so easy in Wizard script that 12-year olds can write it. It would be far easier from my point of view to give me true multithreading, and let me code scripts and triggers the way I want and leave it up to me to manage my own synchronization instead of forcing me into a 100% event-driven paradigm.


EDITTED OUT FIRST PARAGRAPH DUE TO RE-READING ORIGINAL POST.

As someone who dabbled in scripting zMUD for Gemstone 4, I know that they use many different conventions for Stormfront than they do for other clients that accept GSL codes. A lot of Stormfront can be reproduced in zMUD except for those things (main example is linkable text in room descriptions as these things don't get sent out in gsl.

Don't know about multiple roundtime concerns at the same time, though there may be. It isn't that difficult. There is a finished script in zMUD for roundtimes.
Reply with quote
Zugg
MASTER


Joined: 25 Sep 2000
Posts: 23379
Location: Colorado, USA

PostPosted: Wed Sep 06, 2006 5:20 pm   
 
Also, don't forget about multiple trigger states. With multi-state triggers you can actually implement a full "state machine". And "state machines" are an excellent way to deal with complex loops and conditionals. Remember that you have full control over the trigger state and can change it in any of the triggers (or other scripts), so you don't even need to have the states executes sequentially.

You won't see multi-threaded stuff added to CMUD any time in the near future. I have a lot of experience with multi-threading (and CMUD *is* multithreaded in many areas). And what I have learned is that it's a *very* advanced topic and probably the easiest way to completely screw up your program and make it unreliable. Without very careful design, your threads can lock and cause all sorts of obscure crashes. Especially with anything that has a user interface, like CMUD. The Windows GUI API is not thread-safe, so anytime you interact with the user interface, it must be synchronized with the main thread, and that causes lots of locking issues. The concept sounds great, but the implementation is harder than most people believe.

What Larkin posted is correct...there isn't anything that you can't do in zMUD. It just takes a different way of thinking. It's like learning object-oriented programming the first time. At first you wonder why anyone would bother and you wish you could just write stuff the "old way". Then, once you get the hang of it, you wonder how anyone could use anything else.

zMUD (and CMUD) are the most powerful and versatile MUD clients available. But along with this power and flexibility comes a requirement to learn new things. If someone doesn't want to learn new things then they are welcome to use "simpler" clients.
Reply with quote
Larkin
Wizard


Joined: 25 Mar 2003
Posts: 1113
Location: USA

PostPosted: Wed Sep 06, 2006 9:38 pm   
 
Good point on the multiple trigger states. I had forgotten to mention that. I've implemented lots of state machines in zMUD, and those trigger states are almost indispensible. I remember when they were first added to zMUD and how much fun I had figuring out how to use them (and then trying to explain to others what the heck I was doing). I'm still finding fun, new tricks to perform with trigger states, in fact.
Reply with quote
Merzbow
Beginner


Joined: 02 Sep 2006
Posts: 10

PostPosted: Wed Sep 06, 2006 10:21 pm   
 
Zugg wrote:

You won't see multi-threaded stuff added to CMUD any time in the near future. I have a lot of experience with multi-threading (and CMUD *is* multithreaded in many areas).


Multi-state triggers in a single thread already bring in all of the problems of multithreading with none of the advantages. Here's why:

First an example of the way I think things should be done:

http://lich.gs4groups.com

Look at Lich - it's an open-source utility written by a guy as a hobby. It can be configured to layer over any MUD client, like Stormfront or Wizard, and provide access to any scripts you can write in Ruby. It can run any number of scripts in any number of threads that sit around parsing incoming lines and doing whatever they need to do. All synchronization primitives are available so it's up to you to serialize the scripts' access to any shared data that you maintain. This is not hard to do, anyone can write two pieces of code designed to run independently that use a single mutex or whatever to protect a single piece of data.

This is strictly superior to multi-state triggers in ZMud. Why? These triggers, by definition, execute one state, then exit, then the state of another multi-state trigger executes, then exits, and so on. You can only do interesting things like store character info and spellup if there is shared state to modify and read, like a character database or set of variables. Without synchronization primitives, which require real threads, you can't protect the data. This is exactly what Lich scripts do well - because they run in real threads you can protect shared data with sychronization primitives. And between context switches between threads you can store local information in local variables and keep your place in the script because the local stack is preserved.

In contrast, multi-state triggers that are multitasked in the context of a single thread like ZMud are the worst of both worlds. Shared data cannot be protected as explained above, and because you can't use #WAIT you can't modify shared data based on incoming MUD text without exiting your state and re-entering your trigger in the same or a different state, during which time another trigger could run and screw up your data.
Reply with quote
Larkin
Wizard


Joined: 25 Mar 2003
Posts: 1113
Location: USA

PostPosted: Thu Sep 07, 2006 2:39 pm   
 
Almost everything in that post is incorrect. Multi-state triggers combined with other tricks gives you more advantages beyond what threads do for you with none of the disadvantages. I still say it's just a different way of coding that you are resisting because you perceive other script languages or tools to be superior.

Give us a solid example of something you want to do with #WAIT or with a thread, and we'll give you a better way to do it without them.
Reply with quote
Seb
Wizard


Joined: 14 Aug 2004
Posts: 1269

PostPosted: Thu Sep 07, 2006 2:56 pm   
 
Well, Merzbow, if you think Lich is the bee's knees, then why don't you just use that? Personally, I can't think of any reason why I would need multi-threaded scripts, and prefer the event-driven model.
Reply with quote
Zugg
MASTER


Joined: 25 Sep 2000
Posts: 23379
Location: Colorado, USA

PostPosted: Thu Sep 07, 2006 5:08 pm   
 
Have I got an application for you! It's an open-source, multi-threaded, object-oriented Ruby on Rails extension for Eclipse. It was developed by a self-directed, agile workteam employing UML, Ajax and extreme programming techniques. According to Slashdot, Google is already investing heavily in it and calls it the next killer SOA for the Web 2.0.

Seriously, if you want to use Lich, go right ahead. I'm sure anyone using compiled CMUD scripts would be happy to go pvp with you any day.

Once again, this thread has nothing to do with CMUD beta testing.
Reply with quote
Merzbow
Beginner


Joined: 02 Sep 2006
Posts: 10

PostPosted: Thu Sep 07, 2006 6:29 pm   
 
I see nobody has responded to the points raised in my post. If I'm wrong then every modern operating system is wrong also. Look at any Linux or Windows - you'll find many persistent processes running as daemons that wait on any number of events and continue execution when woken. They have execution stacks and local variables and can synchronize access to shared resources. Plus they run as a unit, and can be tracked and killed as a unit. With ZMud triggers you have no local variables, you have no stack so you must re-enter from the top every time, you must explicitly map out every one of your desired states, and cannot safely share resources. Plus you get temporary triggers, alarms, and whatnot that proliferate all over the place to accomplish a single task. It's state-of-the-art circa 1982 folks. Anyways, there's obviously no chance I'm going to change your minds so adios.
Reply with quote
Kjata
GURU


Joined: 10 Oct 2000
Posts: 4379
Location: USA

PostPosted: Thu Sep 07, 2006 9:54 pm   
 
Merzbow wrote:
Plus they run as a unit, and can be tracked and killed as a unit. With ZMud triggers you have no local variables, you have no stack so you must re-enter from the top every time, you must explicitly map out every one of your desired states, and cannot safely share resources. Plus you get temporary triggers, alarms, and whatnot that proliferate all over the place to accomplish a single task. It's state-of-the-art circa 1982 folks. Anyways, there's obviously no chance I'm going to change your minds so adios.


It seems that you are failing to see how multi-state triggers work.

In CMUD, scripts are able to use local variables. These variables go out of scope when the script finishes and cease to exist, so your point about lack of local variables and stack is invalid.

Multi-state triggers do not loose their state once one of the scripts for one of the state finishes executing. The trigger will simply go to the next state and wait for the appropriate trigger for that particular state (which doesn't have to be some particular text from the MUD, it can just be a specific amount of time that has elapsed), or if it is at the last state, it goes back to the initial state. Additionally, you can even define states so that they don't advance to the next state once it is fired, instead you have complete control of when it advances to the next state. You point about lack of state in triggers and having to re-enter from the top every time is invalid too.

Resources can be shared safely with no problem. In fact it is because of the lack of separate threads for each trigger that you can safely share resources. You are guaranteed that no other script is running (and thus able to modify variables, etc.) while your script is running. So that point is invalid as well.

Finally, using once more multi-state triggers, there is no need to have countless temprary triggers and alarms for every little thing. These can be kept to a minimum for cases when they are actually needed. So this final point is invalid as well.

And about the "state-of-the-art circa 1982" comment, please think about these kind of comments better before insulting someone's work like this. I'm sure you wouldn't like it very much if it is done to you.

I'll leave you with a challenge if you are still not convinced that multi-state triggers are the solution for your problems. Present me with any possible task that you can conceive, no matter how complicated, no matter how many times it has to wait for some timeout from the MUD to expire, and I'll present you with a simple, elegant solution that accomplishes what you ask without cluttering up your settings with unecessary items and without using #WAIT.
_________________
Kjata
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Thu Sep 07, 2006 11:29 pm   
 
I will further back up Kjata's challenge saying I can present at least 2 other solutions that will work in the current zMud scripting engine, and that they will be sufficiently different from each other and Kjata's solution as to be called unique. As CMud is still in its infancy and beta stages I am not going to make claims, beyond saying that the proposed and thus far demonstrated improvements in scripting abilities are a vast leap over what zMud had.
Merzbow wrote:
If I'm wrong then every modern operating system is wrong also. Look at any Linux or Windows - you'll find many persistent processes running as daemons that wait on any number of events and continue execution when woken.
The keyword there being events. If you actually had any true programming knowledge you would understand that every one of those threads is polled almost continuously to see if it wants to respond to any of the events that occured. Every keypress is an event. Every movement and click of the mouse is an event. A window being moved, maximized, minimized, restored, resized, etc is an event. In nearly all cases all events are presented to every loaded proccess and they have a chance to respond, most of time though the response is a pass. All current "multi-tasking" operating systems are event driven.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
BlackSmith
Apprentice


Joined: 08 Dec 2002
Posts: 152

PostPosted: Fri Sep 08, 2006 6:08 pm   
 
In game what i play, a battle round lasts ~3 seconds.
In the start of it, i run a simple scan on my targets after a 0,5 sec delay.
If i would do that with #WAIT, i would not need to encounter even lot of lag to my scannings to give results too late. Addition to that, my other 372 triggers are onhold because the damn program is on WAIT.
On the otherhand, with #Alarm +.5, all runs 99% of times just fine opposite to that with #Wait i got 99% of times everything going straigth to hell.

#Wait might be easy when starting to do "coding" but it will backlash on you ASAP you got any triggers that could be triggered after your #wait command.
Trust me, you want to do it and learn it "right" in first palce.
_________________
BatMUD Best MMORPG around since 1990 telnet://bat.org:23
~ Magic & Mind beats Chrome & Meat anytime ~
Pattern(s) in PERL. Using Cmud 1.34/2.09 & BatClient.
Reply with quote
edb6377
Magician


Joined: 29 Nov 2005
Posts: 482

PostPosted: Sat Sep 09, 2006 7:45 am   
 
I have situations where i use both although i can honestly say its more than likely out of quick fixes to coding that i need.

I.E. i want to fire off triggers in the class but need to #WAIT To keep it from firing off right away as it runs the commands i started as well as to #WAIT to #t- it until after everything has processed since it has no unique end firing string and the times are different based on the displays i ask for.

Mostly laziness but its effective to keep things from firing till that script is done.

Alarm is nice but i try to keep those to a minimum as well
_________________
Confucious say "Bugs in Programs need Hammer"
Reply with quote
Display posts from previous:   
Post new topic   Reply to topic     Home » Forums » CMUD Beta Forum All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

© 2009 Zugg Software. Hosted by Wolfpaw.net