Stage 4

Introduction

At this point, you should have a MUD which multiple people can connect to over the network, but they all control the same player. You’ll be fixing that in this tutorial, by supporting multiple players in your server.

Logging in

The first thing we’ll need is a way for people to say who they are, so we’re going to add a way for them to login to the server using a username and password.

In order to allow players to register, if a username doesn’t exist when the player tries to login, the server will create a player with that username and the password they gave (which will they’ll then need to use for all subsequent logins).

Note

Since the networking library we’re using doesn’t support TLS (secure network communications), you should make it clear to your users that their password can be trivially intercepted, so they shouldn’t use a real password.

On the client

After the client connects to a server, the first thing is must do is send a login USERNAME PASSWORD message, and get back a session token from the server. Then in every subsequent interaction with the server, the client will include the token, so the server knows who sent the command. This avoids the client needing to keep the password stored and also gives the ability to log out users.

What you’ve probably realised is that you need some way to send multiple bits of information from the client to the server: not only do you need to send the string they typed, but also the token. This is where JSON comes in handy again: rather than inventing our own format for sending both the token and the line (and probably getting it wrong), we can just send JSON objects between the client and server:

import json

client = Client('mud')
client.find_server()

def send_json(obj):
    data = json.dumps(obj)
    return client.send(data)

token = send_json({
    'action': 'login',
    'username': 'bob',
    'password': 'shoes',
})

send_json({
    'action': 'line',
    'token': token,
    'line': 'look',
})

On the server

This section will require a little more effort. We’ll start by adding two new parts to the data file: a players dict to track all information belonging to a player, and a sessions key to tell us which user a token belongs to.

This is what you should put into the data file:

{
    "players": {},
    "sessions": {}
}

But this is what it will look in the server, after a user has registered and logged in.

{
    "players": {
        "bob": {
            "password": "shoes",
            "location": "main hall",
            "inventory": ["key-1"]
        }
    },
    "sessions": {
        "b2919143f2a24d093b3739e7dfdc9920": "bob"
    },
}

Once you’ve done that, there’s a few things you’ll need to do to the server:

  • handle logins and registrations
  • verify the token on each request they make
  • use the player dictionaries to store the player’s location and inventory

Basically, you should refactor your code to look something like this:

def handle_login(username, password):
    # check the username and password are valid

    # if the player doesn't exist, create them

    # generate (and return) an unused session token

def handle_line(player, line):
    # move everything which was in your handle() function here

    # rewrite the bits using global variables (room, inventory) to use
    # player['location'] and player['inventory']

@server.handler
def handle(data):
    obj = json.loads(data)

    if obj['action'] == 'login':
        # call handle_login with their username and password

    elif obj['action'] == 'line':
        # use obj['token'] to find the user's session in WORLD['sessions']
        # use their username from there to get their player dictionary
        # pass that into handle_line()

    # take the response from the handle_* functions above,
    # encode it as JSON and return it.

Table Of Contents

Previous topic

Stage 3

Next topic

Stage 5

This Page