Skip to Content

1400h, October 27th 2019

1400h, October 27th 2019 is a log tagged with qtMUD, Racket, and programming. It was released on Oct 27, 2019.

In my previous log entry I talked about how qtMUD would work by answering some questions about it, viewing it as essentially just a really big function. I feel like that did an okay job of explaining how the software would work as a server, but didn’t really address how it would function as a game engine.

Before going further, I should specify that I’m not really concerned with scale at the moment, so recognize that some of how I’ve outlined things should work would not be feasible for a game world of many ten-thousands of things, or hundreds of users.

What I’m going to explain below is, more or less, how qtMUD functions, in its most recent implementation as a Python 3 package. (I might end up renaming this Racket engine as something else, but I haven’t decided what yet.)

First I’ll cover what happens when the engine is started, and then I’ll explain what happens when a client connects. Both of these things will only vaguely touch on the sorts of data structures discussed in the last log.

When qtMUD is started, it calls three functions, assuming the previous succeeded (returned true): load(), start(), and run().

Loading the engine means loading the configuration file, first, which among other things has a list of subscribers and services. These define what the engine is capable of.

Subscribers are functions that will be called when a relevant event is scheduled. In the current Python implementation of qtMUD, here’s the extant subscribers: broadcast(), client_command_parser(), client_disconnect(), client_input_parser(), client_login_parser(), send(), shutdown().

You might can infer that there are three different parsers, which are used depending on the client’s situation: are they logged in, logging in, or just connected, basically. broadcast() itself just serves to schedule send() for a bunch of clients - send() takes a recipient and text and, well, sends the text to the recipient.

To call, for example, the send() subscription, one would use the line of Python:

qtmud.schedule('send', recipient=susan, text='Hi Susan!')

Thinking back to the applied function design recipe from last log, I guess it should be added that requests are converted into events, which call subscriptions and those subscriptions in turn create events that send the response. So saying that the program takes requests and sends responses is accurate, but diminishes the disconnect of subscriptions. (Why subscriptions? They allow for linear progression of time and things staying in roughly the same order they were requested in. A lot of “why” has to do with this being, at its heart, a game engine.)

So if subscriptions are the functions that process events, which are triggered by client events, what are services?

Services might otherwise be called daemons. They’re mini-programs that provide the capabilities that make the engine go. For example, in the Python version of qtMUD, there is a MUDSocket service, which controls the socket server which clients use to send requests via telnet, and the Talker service. (The Talker service doesn’t actually need to be a service, so we’ll ignore it for now.)

After being loaded, qtMUD starts itself, which means starting each of its now-loaded services. In the case of the MUDSocket service, this means binding itself to the appropriate port.

Then, qtMUD runs, which means calling a tick() function, well, as fast as it can, because again, this isn’t being built for scale.

Every tick(), each scheduled event is processed, meaning the relevant subscription is called with the matching arguments. Also, every active service that has a tick() function has its tick() called. For MUDSocket, that means reading any requests that have come in, and sending out any responses that have been queued.

So, basically, qtMUD gets everything ready and then handles sending out events and ticking services.

So what happens when a person connects to the engine - that is, enters telnet 4242?

On the next tick, the MUDSocket service starts its tick by looking at every active connection it has. It would notice that one is new, and it would accept the connection, which would be a socket object and the network addres the object is at. It’d create a new client Thing and give it:

Finally, the engine would schedule a send event, with the client Thing as the recipient and a predefined splash text, prompting the client for their (desired) username as the text.

The person would then enter their desired username, rajeev, and hit enter.

While the person was typing, qtMUD kept calling its tick(), which kept calling the MUDSocket service’s tick(), but there wasn’t anything to do so nothign happened.

But after hitting enter, the MUDSocket would catch that there was new data on that connection on its next tick(), and convert it to a string. It’d look up the client Thing associated with that connection, and set it as the value for that Thing’s recv_buffer quality.

It’d also schedule another send() event, just sending the line, verbatim, back to the client. It’d also schedule a client_input_parser() event, with the client Thing as the client and the recv_buffer (more or less) as the line to be parsed.

The client_input_parser event looks at what the passed client Thing’s input_parser quality is, which we set to “client_login_parser”, and schedules a new event for that subscription, forwarding on the line.

(Phew, this is a lot of jargon!)

The client_login_parser subscription is hacky and complicated, so I won’t explain how it works. It validates the client’s password and if it’s correct, gives more qualities to their client.

I won’t get into all that - what I’ve covered was dense enough. Let’s sum up.

When qtMUD is executed, it loads into itself a set of subscriptions and services. It then starts those services which need it, and begins to tick. Services and client requests cause events to be scheduled, which are then called on the next tick, scheduling new events. Events either modify the qualities of a thing. Some services monitor the status of a collection of things qualities, and send responses to connections based on those qualities.

In my next step in planning to develop qtMUD, I’ll be looking at different ways I can write documentation in Scribble, so I can begin to template out the implementation of this process.