[vworld-tech] Web Browser as Interactive Client
Donovan Preston
dsposx at mac.com
Sun Jan 25 22:44:02 PST 2004
On Jan 25, 2004, at 2:18 PM, ceo wrote:
> Brian Hook wrote:
>>> you think about it - do you really need it?
>> It's also a client available right now, so I can do server
>> development and defer client development later.
>
> I agree this is very valuable indeed. However, IMHO web-browsers are
> now a more sensible choice for this, where possible.
>
> For someone trying to get experience of "traditional", old-skool MUD
> design and dev, www is not a good idea because it makes the GUI much,
> much nicer than a traditional MUD :P.
>
> There are many people doing serious, boundary-pushing, work in MUD's
> these days, and AFAICS it's usually nothing to do with "loving the
> feel of that old line-based (can't bind to keypresses!) UI". IMHO a
> crappy telnet client is NOT one of the fundamental advantages of a MUD
> (although the *ubiquity* of said client certainly is...).
>
> The only serious reason I've seen not to use www as your LCD UI is the
> lack of push in the HTTP protocol. You can easily work around this,
> and although many people create special non-www clients (e.g. embedded
> java clients, because web-browsers are too rigidly pull-based in their
> design) to speak their "embraced and extended" version of RFC 2616,
> this isn't at all necessary.
I agree completely. Back when I started hacking MOO, the WWW didn't
exist yet, but I guess around 94 or 95 people started experimenting
with writing HTTP servers in-MOO and I wrote my first webapp in
moocode. The possibilities of combining the moo server with hypertext
were pretty compelling, but I think people quickly became disheartened
by the lack of any way to push updates to the browser and wrote off the
idea as infeasible.
Around this time, wanting to continue development of a multimedia moo
experience, I began writing a standalone client which would be able to
display pictures, play sound, respond to clicks and drags, et cetera,
but it got bogged down in the difficulties of developing cross-platform
applications. (I was mostly using the Mac and wanted to support the PC,
but Windows 95 hadn't even been released when I started development!)
So, I put the project aside. Fast forward 10 years...
> A litle lateral thinking can get you to a very effective MUD whose LCD
> UI is a web-browser which supports meta refreshes (which means all of
> them, these days). There's *very* little difference between a MUD with
> a global 1-second tick, and a framed webpage with a chat-window
> running on a 1-second auto-refresh...
When it comes to LCD, this is even more common than a telnet client.
*Everyone* has a web browser that can do meta refresh. Not everyone has
a telnet client, and even fewer still know how to use it. Even if you
really, really want to support telnet for that x% of your hardcore
userbase, this fact should at least invert the priorities, putting the
web UI first.
> But you can get waaaay more interesting (and powerful, and
> easy-to-use) than that, without making your job as
> server/quest/content coder/author significantly harder. In fact, I
> have a hobby-project at the moment... I promise I'll post when (if) I
> have something interesting to see :).
I'm interested in knowing what sneaky tricks you have up your sleeve,
because I have a bundle of my own :-) Let me enumerate.
First, let me outline the requirements: We would like to have the
ability to push server-side events to the browser, without the browser
polling for these events. We would like the ability to update the
client-side page without refreshing the whole thing, as this can be
slow. We would like the ability to send client-side user input to the
server without refreshing the whole page.
And some anti-requirements: I'd rather not use Java applets. I'd rather
not support Netscape 4. (All for moral reasons...)
My first successful in-browser client was built using frames. Each
frame has it's own src attribute, and the browser loads each frame
separately. When you first load the page, the initial splash screen
goes on the main visible body of the page, and two invisible <iframe>
elements are placed at the bottom of this page. One is labeled "input"
and the other is labeled "output".
The browser then attempts to load these two iframe documents using
individual tcp sockets (glossing over HTTP/1.1). Since the user hasn't
provided any input yet, the server responds to the input frame with a
dummy page. However, the server responds to the output frame by writing
a little bit of data and then stalling. And here is the bit of magic:
Assuming the browser supports HTTP/1.1 chunking (which every browser
does nowadays), the server can hold this socket open indefinitely,
writing noops regularly to keep it alive. Then, in response to a
server-side event, the server can write a chunk of data with a <script>
tag containing the JavaScript to execute on the client.
The JavaScript you write is then similar to any other sort of
client-side DHTML one might write (Which is to say, laden with bugs and
cross-browser incompatibilities ;-) You could use a script to swap an
image (your health meter) or change a number in a text box (your
health). However, there is one technique which works reliably
cross-browser on modern browsers which I prefer to use: innerHTML.
The innerHTML property allows you to... wait for it... change the HTML
inside a particular DOM node. If your server had enough information
about the current HTML contents in the browser, and had been careful to
place unique id= attributes on all of the nodes which could possibly
need changing, then this property can allow you to make dramatic,
sweeping changes to your pages without really writing much javascript
at all.
Sending user input to the server is perfectly straightforward and easy.
You place javascript event handlers on all of your input devices
(<input> text boxes, buttons, images, etc) and in these handlers,
change the src attribute of the "input" iframe, encoding the arguments
you wish to send to the server in the URL. You will want to write a
client-side queue of events so you don't start writing a new event to
the server before the first event has completed being sent.
This technique will work reliably on ALL modern browsers. If you switch
to using regular frames instead of iframes and restrict yourself to not
using the innerHTML trick, this technique can even be used on Netscape
Navigator 4 (shudder). There are even a few more advanced techniques
which are even nicer and more reliable: One involves embedding a small
invisible Flash movie in your page and using the Flash XMLSocket, which
is persistent and can both send and receive (can't send null bytes,
though). The other involves using the browser-specific XmlHttpRequest
APIs (In Mozilla; Internet Explorer has another,
similar-but-not-the-same API). The XmlHttpRequest technique is
functionally identical to the iframe technique, except the browser
"loading" indicator will not continue to throb, as happens with the
frame technique.
But you don't want to use any of these techniques ;-) What you really
want to do is use my web application framework Nevow, which abstracts
all of these techniques away from you, does the browser sniffing for
you, and lets you write python code like this:
form(onsubmit=liveevil.handler(self.onExamine,
"getValue('examineWhat')")
Where self.onExamine is a server-side python function, and
"getValue('examineWhat')" is a client-side JavaScript function which
will be called and whose result will be passed to self.onExamine.
Nevow is available now in CVS for the brave. All that remains to be
done to package it standalone and make it easy to install is to remove
some convenient dependencies; it's on my todo list and I should get to
it around the end of the month. The liveevil module, which is a rewrite
of my earlier LivePage efforts, is proving to be quite usable and
powerful. I am currently writing a browser-based clone of the old
MacMOOSE GUI client which allowed you to introspect MOO objects, edit
properties, and program verbs using nice GUI tools. I will write more
about Nevow and post some simple examples of how to use it to connect
to your MUD (my moose client is less than 200 lines) when I have an
easy-to-install distribution.
dp
More information about the vworld-tech
mailing list