Game Server Code Design – Best Practices

Architecturedesigndesign-patternsobject-orientedserver

I'm designing a multiplayer game server where the players are in rooms. Right now I have classes to take care of the client, networking, etc. I'm struggling however to find a design for this Room class. For example, when I want to change a client's room, should I call client.changeRoom(newRoom) or newRoom.addClient(client)? What about when leaving a room, should a client detach itself from the room or the room detach the client? I'm very confuse here, I just don't want to end up with a design I will regret in the future.

Best Answer

With flashbacks to my LPmud days, the answer is the client (player, object, ...) is moved from one room to another and notifies the previous room (and everything else in the room) of this fact.

Upon entering a new room, the client again notifies all things in the room of its entry.

Not all rooms (or things in rooms) care about this fact and can quietly ignore this message.

The way the LPmud design works is that the room is "just" a special type of object with connivence functions for linking it to other rooms.

The design of the room doing the moving of a player from one location to another means quite a few more lookups.

Note: I'm using getRoom() here as an example function. The method might have been getEnvironment() which returns the container an object is in... and all objects had a container (an coin in a bag in a player inventory coin-> getEnvironment() would get the bag and coin-> getEnvironment()-> getEnvironment() would get the player, and coin-> getEnvironment()-> getEnvironment()-> getEnvironment() would fetch the room...)

The player would need to do a me->getRoom()->moveMeTo(newRoom); to move around. This gets a bit cumbersome and sometimes, when things go wrong, you don't have room that you are in which would make it impossible to move to another room.

The thing with the 'intelligence', the thing doing the acting is the player, and thus that should be the thing doing the acting in the room.

me->getRoom()->notify_all(me,leaving);
me->moveRoom(newRoom);
me->getRoom()->notify_all(me,arriving);

Before you point out that I said me->getRoom()->moveMeTo(newRoom); was bad above and yet use me->getRoom()->notify_all(...) above, the difference is that in the case that the client is not anywhere, the getRoom() would return a null object that ignores all messages and so nothing goes wrong there. However, in the moveMeTo approach, the null object would ignore all messages, and you wouldn't get anywhere.

As an aside, you might want to download an LP mudlib to look at it and consider how the various components are architected. A lot of design thoughts have been put into it over the years that probably represent many programmer-decades of refinement.

The locations of hooks, connivence functions, and structure, when looked at can make some of your own decisions easier to come by, understand, and reconsider.

Related Topic