[MUD-Dev] Event handling (was: request for comments)
JC Lawrence
claw at under.Eng.Sun.COM
Sun Jan 11 12:43:54 CET 1998
On Fri, 9 Jan 1998 13:51:24 PST8PDT
s001gmu <s001gmu at nova.wright.edu> wrote:
> On Fri, 9 Jan 1998, Vadim Tkachenko wrote:
>> s001gmu at nova.wright.edu wrote: > > On Thu, 8 Jan 1998, Vadim
>> Tkachenko wrote: >
> *nod* our end goal is to not make it obvious to the player that the
> game is turn based, but the underlying mechanics will be. The more
> that I think about it, the less I like the 'tick' idea... Why
> artificially impose a less granular clock on top of the system
> clock? Why not just let the system clock determine the timing?
> Situations where the character's speed should be far faster than the
> players typing speed (IE: combat, etc), can (and should?) be handled
> by the computer (IE: the computer is generating the events, not
> player commands). All other commands don't need to be turn-based,
> as speed has already been deemd uniportant by the designer (me), by
> that system not being coded as an auto-generated event.
This sounds very much like the the argument I went thru with myself.
>>> but when I tell my character to "cast fireball at bubba", it
>>> becomes trivial to implement the delay inherent to the action by
>>> scheduling the event to go off 3 ticks down the road.
>>
>> By the way, this is exactly the point where extra threads appear in
>> my model. Every time-based action is asynchronously handled by the
>> separate thread, which allows to handle effects like spell
>> backfires, concentration, partial force release, accumulation
>> rules, side effects with extreme ease.
> *nod* I think I see where you are going.. the event, "cast spell" is
> plunked on the queue, and handled as quickly as possible. Handling
> means calling a method which may "sleep" for a while, to take care
> of the delay.
Ouch -- that's a very expensive route. Cheaper:
The initial event parses the "cast fireball" command and logs an
event to try and cat the fireball.
That event then runs aaaaaaaaand determines if a fireball can be
cast, and when. It then logs a new event to cast the fireball then.
That event then ripens in XXX time and the fireball is cast.
Nothing goes to sleep, no resources are wasted, all the events are of
minimal size and resource loading.
> If it's interrupted while sleeping (someone interrupts bubba casting
> the spell), you have some sort of 'interuppted' method which handles
> the results of someone busting up bubba's concentration. Right?
This gets tricker. THe above format forces all events into the
structure of:
1) Check that the event is still valid (the event is to do X, and X
is still possible? ("Hit Bubba" and Bubba is no longer present)).
2) Do the deed.
In the case of sensitivity to interruption I currently handle this
poorly (almost not at all).
However, previously I discussed having the system track the osers
activities, and from that attempt to determine that they user's
_intentions_ are. From there it can appropriately attempt to filter
the available data against a dynamic LOE (level of expectation) filter
which changes as the system changes its understanding of the user's
goals.
This may be extensible to handling interruptions. Essentially (all
Wiggin's solution) the server would track the activities (of duration)
that the user is engaged in, and dynamically remove and add entries as
the world changes. Some things would get deleted from the list (you
cease to dig the Panama Canal as the world is obliterated by a passing
Vogon fleet), and others would merely be surpressed temporarily (you
pause in digging the Panama Canal to eat a vegemite sandwhich before
returning to digging).
> That being the case, I'd still prefer to let events spend their
> delay time on the queue, instead of in a thread. Each sleeping
> thread is a thread that could be used by something else. Why
> allocate a scarse resource before it's 100% needed? Again, this
> harks back to my initial goals, of building a non-cpu intensive
> game... well, at least, less so than other games... ;)
Precisely.
> mmm.. I dunno that that is really a valid concern... I am leaning
> more and more towards JC's Spoof/Watcher model, which allows for
> such things nicely (definately planning on spoofs.. still thinking
> about watchers..
Spoofs and watchers have different function, altho their capabilities
can cross. The intent of a watcher is purely to tragger on sate
changes. This allows objects to react to changes in other objects:
Bubbaa stands on the end of a balanced see-saw. You give him a
rock, and the see-saw will topple his way. The cannonical scenario
here was Bubba and the Crystalline Tree where the challenge was making
the tree suitablely fragile for all the ways that Bubba might be able
to get into it including counting the ways his weight might change
while he was in the CT. eg:
Bubba teleports into the tree (can't do the weight check in the
"climb" process).
Bubba is hanging onto balloons while he climbs the tree, which he
then lets go of once in the tree (same as before, but the climb
process validated the weight, which has now changed).
Bubba is lighter because of a "fly" spell which is then cancelled
(variation on teleport and "entry checking" ala climb process).
Boffo teleports a heavy object into Bibba's pack.
The gravitational constant changes for that part of the world
_after_ Bubba is ine the tree.
etc...
I wanted a general solutionw hich could elegantly handle all of these
without special casing.or requiring bizarre design or coding rituals.
> dunno if my design goals necessarily coincide with
> the ones you chose that lead to spoofs/watchers, JC).
I presume this means that requirement that any feature must be able to
be programmed without requiring source access to any objects other
than the ones embodying the featuer?
> W/O using
> watchers (to watch the phase of the moon), I would schedule an event
> to go off at the beginning of the time the lycanthrop should morph,
> to trigger the morph, and then one to go off at the end of the time,
> to morph the poor bastich back.
What happens if Bubba manages to delay or accellerate moon-rise/set?
What if this was thru administrative errors (Admin reset the time and
forgot some details)? You are creating an indepedant system which
does not rely on or react to the data which it pretends to be
dependant on.
There are two base approaches: watchers and messages.
In the watcher case all lycanthropes merely matain a watcher on the
relevant moon object and respond accordingly. The moon
sets/rises/whatever, the watcher is triggered and they have a chance
to react appropritately.
In the message passing case the moon state-changes and realises that
other objects may be dependant on that state change, and thus sends a
message to them, or directly invokes their methods to make the changes
itself (ugly).
There really is very little difference here from the watcher model
except that it is now the object itself determining that the state
change is relevant, and the object itself also now needs to maintain
its lists of who to send the state-change messages. Watchers just
virtualise this model by having external generic non-invasive objects
do all the work of triggering and sending the messages.
The programmer for the mood doesn't need to know a thing about
lycanthropy or wolves howling, he just needs to account for the moon.
Similarly the programmer for the were-wolves doesn't need to hack the
source for the moon, he just has his were-wolf objects put a watcher
on the moon (a very standard, on-line command), and then writes a
couple lines of code to look for the state-changes he is interested
in.
> No real worries about multiple
> events targeting the same data at the same time, as the events would
> occure once a month! :)
Until Superman gets that moon spinning faster in a lower-orbit.
> I'm thinking the best solution might be to fall back on DB
> backups... every <so often> the program dumps a 'current state' of
> the pc to the DB. if a crash occurs, the last 'current state' is
> loaded. Current states would include enough info to reconstruct the
> events for the character in question. Some events would have to be
> handled seperately... combat type events, etc. mmm.. definately
> requires some thought. Mayhaps I shall go dig up my concurant
> software design notes, and DB notes on rollback techniques.
One of my early design had the DB do periodic saves to backups. The
problem as you note was maintaining logical consistancy for changes to
the DB __during__ the backup procedure without requiring the entire
game to halt during the backup.
It can be done. The solution consists of two parts:
1) for object in DB, write object to backup DB.
2) for object change during backup where object has been written to
backup DB, flag object in backup as deleted, write changed object to
current running DB __and__ backup DB, and update indexes appropriately.
> Bubba and Boffo are fighting. Bubba and Boffo are on different
> clocks for their 'db backup' events. Combat is interrupted by a
> crash / termination / reboot / whatever. If all events are stored
> in the db backup, Bubba and Boffo will have different pending combat
> events, based on the different times at which their last backup was
> made.
True.
> Easy solution, put everyone on the same clock. problem: large db
> writes, all at once. slams system pretty good with a lot of ppl on.
See above. You can make the backup thread quite low priority.
> definately a DB rollback issue.
Nooo. A consistancy issue.
> Any comments from the peanut gallery? :)
More salt please.
--
J C Lawrence Internet: claw at null.net
Internet: coder at ibm.net
----------(*) Internet: jc.lawrence at sun.com
...Honourary Member of Clan McFud -- Teamer's Avenging Monolith...
More information about the mud-dev-archive
mailing list