View Single Post
Old 10-15-2010, 10:08 PM   #2
dayrinni
New Member
 
Join Date: Apr 2002
Posts: 29
dayrinni is on a distinguished road
Re: MUD Development Journal

This post will touch on some aspects of the game engine.

My best friend, Actinate, who was the co-owner of ATS with me can be credited to the name of the game engine that I created. I told him about it over the phone and he randomly screamed "TITAN!" at me. Upon questioning this, he said that was the name of the engine. So this is the Titan Engine. I'm sure this isn't the first engine called Titan, but hey, it is what it is.

As previously mentioned, this engine is written in 100% Java. It contains a few important key points: networking, command parsing, storage, and ASCII maps.

Networking

The networking aspect is particularly interesting. When I was in undergraduate college (many years ago) I took an internet programming class. This class used Java as its language. We did some basic socket programming and I learned quite a bit here. However, I wanted to make it easier to use. So I took about a month and made my own networking framework. It is a polling framework, were there is a single thread and it asks each socket if the buffer has data. If it does, then it'll grab it and then execute whatever its supposed to execute. This helps avoid concurrency issues since everything executes sequentially.

This consists of two portions: how input/output is handled and commands.

Input/Output
There are two modes here: instant and buffered. Instant will do just what it says. When a command comes in or out, it will be executed/written from/to the socket. While buffered will not do this – it will collect all of the input/output from/to the socket and handle the processing every set amount of MS. This MUD uses the buffered option.

Commands
In order to completely remove the socket layer from the programmer, simply extend a Command class and place all of the code in a special execute method, that contains the parsed data from the socket. This allows easy handling of any input from the network. I have used this extensively for other programs and it works beautifully.

Since the MUD simply handles text commands on a single line, we only need a single command to handle typed input. This is called GenericCommand and will handle getting the information from the network, the player who executed it (which is based on the connection) and then passing it to the player's state (see below). There is an additional command, ConnectionCommand, which is used to handle incoming connections.

So from a networking stand point, it was very easy to adapt this framework to the MUD.

Command Parsing

The command parsing is particularly important for a MUD.

Each player has a State (a PlayerStat e class), such as JoiningState, LinkDeadState, and so on. Depending on each one, different typed commands from a player are valid/invalid. For example, if a player is trying to choose their race and they are presented with a list of choices, the RollUpRaceChooseState will ensure that the proper way to handle all of the commands for choosing races occur. So for example, the only valid commands would be a number from a list and any help commands.

The main State, PlayingState, is very basic – it simply passes the command input from the network to the CommandHandler. This will handle parsing the command.

This CommandHandler class will parse the data into an array of Strings. The first index of the array, (yes, the parser checks for a blank line) is looked up in the command list for the indicated command. This is done by a partial match using startsWith on what was typed and what is present in the command list. A sequential search is done. So command placement is important.

If the command is found then the array is passed to the commands execute method. Otherwise, an error message is displayed to the player indicating an unknown command. There are some extras in here, like if a player is dead – they can't do certain actions and another error message is displayed.

The commands themselves, they do parsing on the array. This is bad and I intend to change it. It is very easy to run into exceptions with going out of bounds on the array. So I am going to make a CommandArgument class where it has methods such as, hasArgument(int commandIndex) and getArgument(int commandIndex). In this manner, it is possible to specify what number of command is desired. The indexing will use 0 based, but it will be based on the fact that the first element in the array will be the command typed.

For example, if this was typed:
kill john
"kill" would be index 0, and "john" is index 1 (clearly). So a call to getArgument(1) will return "john".

Code will be placed inside of the CommandArgument class to avoid any nasty exceptions. This will provide a much safer way to gather the command argument information and will be much easier to program the commands.

If anyone wants to talk about this aspect more, fire away. I haven't made the change yet.

Anyways, once the command gets a hold of the array, it will parse data from the contents and execute whatever it is supposed to do.


There ya have it.

Storage

Some games use flat files, others use Databases. The game uses XML. Not much to say here besides there are XML parsers to read in data and XML parsers to write out data to files.

ASCII Maps

The game has the capability of displaying both a map and description in the Room Descriptions. The maps can display characters, enemies, shops, exits, and the like. Pretty standard.

I wanted to be able to have the capability to make lots of maps very fast. So I wrote up a tool that can parse in a .map file and then generate a full blown area from it. The map file contains the physical representation of what it will look like in the game. Each symbol has a specific characteristic to it, such as what color it will be. The game will handle the creation automatically. It will connect all of the exits correctly, as well. Anyone could churn out probably 20 maps a day. Sure, they'd be empty, but hey, we got maps!

Another feature I put it was an automatic exit connector between two different areas. Lets say two huge areas are next to each other and connections were desire on a particular side. Just specify the starting and ending rooms, and which direction to go in (w,e,n,s). The game will calculate everything else based on the input and sizes of the areas. Then ta-da, a fully connected side.

My only issue right now is the fact I have made some very large test maps. I think they are on the order of 40x40 and that is far too much. Each character is color coded and that just adds for a lot of extra data that needs to be sent across the network. If I recall correctly, that is around 6 characters per character on the map for the coloring. It is a performance issue. I have a few ideas to tone this down:

1.Make the maps smaller.
2.Make the characters be able to only see a certain distance, say 5 rooms in each direction and send only that. This would cut down the amount of data needed to be sent greatly. However, code will have to be made in order to get exactly what can be displayed each time a player types look.




The End

Well there ya have it. That is a brief description of some important points of the engine for the game. Hope you enjoyed reading it.

Thanks,
Dayrinni

Last edited by dayrinni : 10-16-2010 at 09:54 AM. Reason: Typos.
dayrinni is offline   Reply With Quote