2004 RuneScape fit a multiplayer RPG into 56k dial-up

Added correction regardingCtrlkey. In early versions this was “force run”, in a later
update it was changed to “invert movement mode”.

In 2004 I played too muchRuneScapeon a 56k modem that died the moment Mum picked up the phone. A 3D world, up to a couple of thousand players on a server, dozens on screen at once – in the browser, on 5 kilobytes per second. It worked. Let’s follow a single step and see how.

As a child I was too preoccupied with picking flax and killing goblins to think abouthowthis worked. The answer, however, is a sustained, almost obsessive exercise in not wasting bytes. So, let’s click one tile north of where we’re standing, and trace every byte that crosses the wire from that click, to the server, to the screen of another player.

The detail in this post comes from a decompiled 2004RuneScape 2client. Snippets are rough translations from that decompile, tidied up in places for readability but with the logic intact.

The core principles aren’t identical across versions, but most of them run all the way fromRuneScape Classic(2001) to present-dayRuneScape 3and, of course,Old School RuneScape.

Let’s look at some of the constraints that Jagex were working with at the time.

After the login handshake completes, before any game packets are sent, a small encryption layer is set up. This one’s not about saving bytes; it’s the only encryption in the stack (outside of some RSA encryption in the login handshake), and it’s here because the opcode it protects is the very thing every later section depends on.

Every packet begins with an “opcode” byte: a small integer saying what kind of packet this is. That opcode (andonlythat opcode) is enciphered with a stream cipher calledISAAC. There are two streams in play – one for traffic from client to server, and one for the reverse direction. Both sides need both streams: the client enciphers what it’s about to send and deciphers what just arrived, and the server does the same in mirror image (per connected player).

Enciphering on the way out is one line:

And on the way in, the mirror image:

So the packet body isn’t encrypted, only the opcode. As we’ll see later, the opcode is what tells you how to read the rest of the packet, and where one packet ends and the next begins. Without it, the body is just a wall of bytes, so enciphering that one byte was the cheapest possible defence against third-party packet parsers.

We’re going to look at what happens when you click on a tile one square north, and how that gets transmitted to the server.