25 Oct, 2009, Erok wrote in the 21st comment:
Votes: 0
Scandum said:
Then there is the human bottle neck, no one will notice the difference between 20 loops per second and 50 loops per second. Not to mention network and OS lag.

Again, it isn't so much the impact on user experience as it is efficiency/elegance within the MUD. Why wake up 20 or 50 times per second (though 4 or 5 is more realistic) looking for work to do, when it's far more efficient to wake up only when there is actual work to do? Event driven isn't any more complicated to implement than polling, so IMO there's no reason to stick with polling if you're developing something new. I know polling is well understood because of it's historical usage in MUDs, but that doesn't make it the best solution.

PS: Don't know anything about tintin++, but why does it poll at all? As a client, I would have expected it to block indefinitely on read. If it's to process user input, why not do that in a separate thread? One could even simply redirect the user input to a pipe for processing by the read thread if access to shared data is a concern.
25 Oct, 2009, Scandum wrote in the 22nd comment:
Votes: 0
Erok said:
Why wake up 20 or 50 times per second (though 4 or 5 is more realistic) looking for work to do, when it's far more efficient to wake up only when there is actual work to do?

20 times nothing is still nothing, so all things considered it's not a big deal, unless you have an inefficient method of polling events.

Erok said:
PS: Don't know anything about tintin++, but why does it poll at all? As a client, I would have expected it to block indefinitely on read. If it's to process user input, why not do that in a separate thread? One could even simply redirect the user input to a pipe for processing by the read thread if access to shared data is a concern.

What'd be the big advantage?
25 Oct, 2009, Erok wrote in the 23rd comment:
Votes: 0
Scandum said:
20 times nothing is still nothing, so all things considered it's not a big deal, unless you have an inefficient method of polling events.

It's not nothing if you also consider the work that the OS is doing to swap in the process for execution. If the CPU has nothing better to do, then no big deal, though I suspect MUD hosts will probably appreciate efficient server designs. Anyway, do what works for you. I jumped into the thread only to ensure the technical arguments were accurate.

Just wanted to add… although this whole discussion may seem to be a bit much in the context of a MUD, which requires few resources from a modern computer, the attitude of not designing for efficiency is what led to bloatware like Windows. I work in embedded software, where resources are limited and efficiency/performance is always a concern. I would think the same is true for other industries, such as financial software (e.g., transactions per second). It's just good practice.
25 Oct, 2009, Scandum wrote in the 24th comment:
Votes: 0
Erok said:
It's not nothing if you also consider the work that the OS is doing to swap in the process for execution. If the CPU has nothing better to do, then no big deal, though I suspect MUD hosts will probably appreciate efficient server designs. Anyway, do what works for you. I jumped into the thread only to ensure the technical arguments were accurate.

Well, we're talking 0.01% cpu usage here, or something of that order, I doubt a MUD host would notice the difference. Regardless, it all adds up, and in that regard you certainly have a point.
25 Oct, 2009, Mudder wrote in the 25th comment:
Votes: 0
I would like to mention, for the MUDs sake that it listed this feature in a section labeled "things you don't care about and probably won't notice" or something like that. I asked the question because I was curious.
25 Oct, 2009, Mudder wrote in the 26th comment:
Votes: 0
Erok. You have me convinced to try out new systems and screw around looking for something better.

What are the thoughts on Runter's event system?
25 Oct, 2009, David Haley wrote in the 27th comment:
Votes: 0
The difference between a tick-based and event-driven architecture isn't at all just a question of terminology, most certainly as far as implementation is concerned. That said, the difference between a regularly scheduled tick event and a tick loop that runs every X time units is indeed negligible. If that's the only thing you do with the event system, it's kind of a waste of effort: the point behind an event system is indeed (as others have said) to wake up only when there is work to do. In this case, if you kept the tick event (and were being clever), you would do rather different work than in the traditional tick loop which requires a full check on everything; you might only do things like reset areas, or events that happen to everything truly once a tick.

Mudder said:
What are the thoughts on Runter's event system?

It has a number of issues. The biggest is that one shouldn't be looping through the entire list of events to find the ones that need triggering. Events should be sorted in order of upcoming events, so that you need merely pop things off the front until things are no longer due. This means that instead of counting down a timer, you keep track of event time as "now + delay", and an event fires if "now" is greater than or equal to the event's trigger time. There are other implementation comments (for example, the comment on line 212 about doubly-linked lists allowing for faster extraction is incorrect) but there's no real use going over the code in detail because it clearly disclaims itself as a prototype of sorts. The issue of looping over events is a more serious design problem.
26 Oct, 2009, Scandum wrote in the 28th comment:
Votes: 0
One thing I'm wondering about, how are weak pointers typically implemented?
26 Oct, 2009, Erok wrote in the 29th comment:
Votes: 0
Mudder said:
What are the thoughts on Runter's event system?

I haven't looked at it, but if you are working with an existing codebase, migrating it to libevent is also an option that has good documentation and user forums.

Scandum said:
One thing I'm wondering about, how are weak pointers typically implemented?

You can refer to the Boost or Loki libraries for example implementations in C++. The Boost variant has been accepted into TR1 and will become part of the C++ language standard.
26 Oct, 2009, Mudder wrote in the 30th comment:
Votes: 0
Erok said:
I haven't looked at it, but if you are working with an existing codebase, migrating it to libevent is also an option that has good documentation and user forums.


Currently I'm using a rom codebase. RaM fire, actually.

I downloaded libevent but have absolutely no idea how to make use of it. It's a library, right? …My knowledge with such things leaves much to be desired.
26 Oct, 2009, Davion wrote in the 31st comment:
Votes: 0
Mudder said:
Erok said:
I haven't looked at it, but if you are working with an existing codebase, migrating it to libevent is also an option that has good documentation and user forums.


Currently I'm using a rom codebase. RaM fire, actually.

I downloaded libevent but have absolutely no idea how to make use of it. It's a library, right? …My knowledge with such things leaves much to be desired.


It looks like this code is meant to replace the entire socket layer. It's quite a modification for someone just starting out :). Might want to consider writing your own.
27 Oct, 2009, Erok wrote in the 32nd comment:
Votes: 0
Davion said:
It looks like this code is meant to replace the entire socket layer. It's quite a modification for someone just starting out :). Might want to consider writing your own.

I'll take a look a SocketMud, and see how much effort it would be to migrate it to libevent. It sounds like it would be helpful to have a reference implementation of an event driven MUD available.
27 Oct, 2009, JohnnyStarr wrote in the 33rd comment:
Votes: 0
Here's my event system idea: (let me know what you think)
I am using EventMachine for the server object. I have an event queue that can schedule
one time or reoccurring events. It can even have events schedule other events. Then, I am
going to use the Observer Pattern to have the game-objects observe each other. Here's a quick
example:
(event queue)-> runs: cleanup_corpses
|
->(room 1300)-> runs: remove_corpse
|
(state of room 1300 has changed)-> notify_observers "A corpse decays into nothing."
|
Aragorn.send "A corpse decays into nothing."
Legolas.send "A corpse decays into nothing."

This seems good so far, but this is pretty new stuff to me, so I would appreciate any constructive criticism.
27 Oct, 2009, David Haley wrote in the 34th comment:
Votes: 0
I'd be careful with being too happy with putting observers all over the place. It gives flexibility at the cost of (sometimes quite considerable) complexity. Observers make sense when it's hard (or sufficiently annoying) to keep track of who should be getting what message, or when "agents" (whatever an agent might be for you – it could be a tree view in a GUI for example) need to sign up to generic event providers and change between them.

In other words, you don't need to have an event framework in which each literal event is represented as an event message that goes through the whole pipeline. You can keep events for the complicated case, and use normal, linear logic for simple cases.

CoffeeMUD does a bunch of stuff with events (it calls them messages IIRC) with things like previewing and modifying them, so you could perhaps take a look at its (rather extensive) code design documentation.
27 Oct, 2009, Tyche wrote in the 35th comment:
Votes: 0
Mudder said:
What does that mean exactly? I thought ticks were themselves an event? I realize that with each "tick" other events are triggered off of this and creates a somewhat machine like feel but how else could this be done without creating other versions of a "tick" and making them fire off other events. In a sense, simply creating a tick for each event type. So how could a MUD truly be "tick free" and purely "event driven" ?


This thread may be of interest to you.

Anyway I pull in my take on events…

Tyche's Immediate Temporal System

Here are the two simple laws of TITS:
# An event is issued at the point of a state change.
# An event is guaranteed to complete.

Events should not be scheduled to occur at some future point in time as events are by their very nature immediate. That is to say a scheduled event is not really an event but a potential event.

Consider the consequences of the TITS-less implementation above. If something should occurred before the scheduled event like an earthquake, flood, or a hole is ripped in the space time continuum that redirects or otherwise voids the destination, then there is no way the event can occur, be completed and will be invalidated. One must handle that. Or consider the consequences of your present TITS-less system. Either way you will be faced with unsatisfactory results unless you embrace and grasp TITS.

There are many others involving causality and logic errors, a few examples:

Inevitable Death scenario:
Bob eats a poisoned apple.
A death event is scheduled to occur in 10 minutes.
Bob takes an antidote to the poison.
Bob dies in ten minutes.

Elves and the Swordmaker scenario:
Bob is crafting a sword
A sword completed event is scheduled to occur in 2 hours
Bob goes to the local pub gets drunk and returns to smithy in time to receive the completed sword

Non-interruptus scenario:
Bob begins casting a fireball
A fireball spell event is scheduled to occured in 2 minutes
Sam knocks Bob unconscious
Bob completes the casting of the spell and a fireball is produced

All of these problems have different solutions depending on how you want the scenario to play out, most involve carefully removing the non-event from the queue or writing additional (code) to carefully check the validity of the assumed state.

Event removal may also introduces new problems…

Item Eaters and the Swordmaker scenario:
Bob is crafting a sword
A sword completed event is scheduled to occur in 2 hours
Someone knocks on the shop door and Bob goes to answer it.
The sword completed event is removed from the queue.
Bob returns to an empty work bench and has to start all over again.

Expanded definition of TITS theory:
# An event is something that happens at a point in time. Now, not in the future!
# An event has no duration. No duration!
# Two events may be said to precede or follow another or may be unrelated.
# Those that are unrelated are said to be concurrent.
# An event is a one way transmission of information from one object or subsystem to another object or subsystem.
# It is not like a subroutine, thus there is no return. An object or subsystem may expect a reply, but this reply would be in the form of an event under control of the second object or subsystem.
# Objects or subsystems are considered to be innately concurrent.

It certainly quite difficult to test and build a system or even generate meaningful event-state diagrams to test your system when you don't know the state! Scheduling events to occur in the future implies that these aren't really single discrete events as they actually have a duration, but actually pairs of events with some unspecified/undefined state that exists in between.

A Ruby implementation of TITS can be found in TeensyMud available at all fine mud code repositories.
27 Oct, 2009, Erok wrote in the 36th comment:
Votes: 0
Tyche said:
Anyway I pull in my take on events…

So without having seen your TITS, I think what you are saying is that an event should be the result of a state transition, of which a timeout can be one of many triggers. Yes, no argument here.
27 Oct, 2009, Scandum wrote in the 37th comment:
Votes: 0
Tyche said:
Events should not be scheduled to occur at some future point in time as events are by their very nature immediate. That is to say a scheduled event is not really an event but a potential event.

You can link an event to an object. When an event is removed from the event hash it's also removed from the object it is attached to, and when the object is removed all events tied to it vanish as well. This at least guarantees data access and integrity.
28 Oct, 2009, quixadhal wrote in the 38th comment:
Votes: 0
Tyche said:
Item Eaters and the Swordmaker scenario:
Bob is crafting a sword
A sword completed event is scheduled to occur in 2 hours
Someone knocks on the shop door and Bob goes to answer it.
The sword completed event is removed from the queue.
Bob returns to an empty work bench and has to start all over again.


So, without having looked at your TITS, would this be one way to model the above safely?

Bob begins crafting a sword.
Event happens, creating an incomplete sword object.
The sword object begins completing itself on a timer, adding a percent
every N minutes that it, Bob, and the workbench are together.
Bob leaves the workbench to answer the door.
Event happens, The sword object stops updating, since Bob is not present.
Bob returns.
Event happens, The sword continues updating, since all three components are present.
The sword's completion percentage hits 100%.
Event happens, incomplete sword object replaced with crafted sword object.
Bob goes out and drinks a beer.

If I'm buying into the theory, each event is a state change, but the actual timer-based actions are not events but listeners which may change their behavior based on events they observe. If the shop catches fire and destroys the workbench, that would presumably generate an event which the incomplete sword would see as a component becoming unavailable.
28 Oct, 2009, Koron wrote in the 39th comment:
Votes: 0
I loathe minute based timers. They're so imprecise. I just had to put that out there.

I would make the incomplete sword object track its timer based on the amount of time (seconds, probably!) Bob was in the room with (bob->crafting_item == this) while unintoxicated, awake and whatever other complications need to be absent to allow proper crafting time. Every second those conditions are TRUE, decrement the timer. To complicate things, you can add stages at which interruptions destroy (or weaken) the final product.

Of course, this is ideal-world stuff. Just because Bob logs off doesn't mean his crafted item is destroyed. If he's whittling a staff, there's no reason to expect interruptions to do anything other than delay completion. Real world complications may arise as you try to decide how to store these states. Woo!
28 Oct, 2009, JohnnyStarr wrote in the 40th comment:
Votes: 0
I trust Tyche on this one, don't get me wrong. But it seems like some additional mechanism is required to accomplish things this way.
For example, what mud doesn't need global events like; respawns, auctions, weather changes, etc? Of course, I can see that you aren't saying
that muds don't need these, because every popular mud has them. It seems like if you passed enough arguments to the event, you could accommodate
for any potential logic conflicts. But then again, I'm not as experienced as Tyche or others yet, so I must be missing something.
20.0/45