DB Classic Multiplayer Tutorial
By TDK_Man
Note: This tutorial was produced using DB Classic with the Enhancement Pack installed. It should apply equally to DB Professional, but definitely will not work if you are using Classic without the enhancements - a very good reason to upgrade your DB Classic!
Introduction
Before I saw a post on the forums asking for someone to do a tutorial on the Multiplayer commands, I hadn't even looked at them before. I have prior experience in Windows comms programming, having written a Windows-based mail client and a chat client (like Windows Messenger), so I knew what to expect.
I took a look at the commands in the help files for the first time and approximately three hours later I had two DB programs running on different machines on my network happily talking to each other.
The point I am making is that at first glance the subject looks very complicated, but when you understand the basics, it's really quite simple...
Basically, the Multiplayer commands give you the ability to write two types of program in DB. One which can act as a server - much like the one the DB forums are located on and the other a client which connects to that server - like your web browser connects to the server to access the forums.
Once the two are connected, you can send data back and forth from one to the other. So, you can write a game with a client section which connects to a server along with other users playing the same game, allowing you to all wander around the same location, fight each other and so on.
It's all a case of passing data around the machines so they all know what the other players are doing.
So, how does it all work?
The first thing to do is explain a bit of the techy terminology for the newcomers...
IP Addresses
When you are using a computer on a network, for it to talk to another one, they both have to be able to talk in the same 'language' as each other. On a network, the language used is called a 'protocol' of which IPX/SPX and TCP/IP are the most common. Most networks these days use TCP/IP and IPX is most often only present as an option on Novell Netware networks.
On a network with many computers, there needs to be a way to make sure that information sent from computer A to computer B goes to computer B - not computer D.
To do this, each computer is given a unique number on the network called an IP Address. This is an octet number - 4 numbers separated by full stops such as 192.168.1.11. Each of the individual numbers can be between 0 and 255, but normally, 0 and 255 are not used. That still leaves enough free for up to 254 computers on the network!
Your IP address when on the internet is normally 'dynamic' (allocated by your ISP each time you connect) unless you pay extra each month for a 'static' IP address which never changes.
On a Local Area Network (or LAN) at home, you would normally use the numbers 192.168,0,x for your machines as this is an 'official' subnet reserved for private use. So for each computer on the network to talk to each other, they must all have the same first three numbers and the last one (where the X is) must be unique.
The internet is just a bigger version of a home or office network but over a wider area, so it's called a WAN (Wide Area Network) rather than a LAN. But it works in the same way using IP addresses. Each computer has it's own IP address and no two machines can have the same numbers.
When you type http://www.thegamecreators.com into your browser, it doesn't know what or where that is. It needs an IP address, so the browser accesses another computer called a Domain Name Server (DNS) which takes the URL and returns the IP address 216.92.119.232 - in much the same way that directory enquiries tells you what auntie Vera's phone number is when you give her full name and address. Armed with the IP address, your browser can connect to http://www.thegamecreators.com.
So to summarize, the machine you are connecting to is the Server and you connect to a server with a Client. OK, so now we know how machines can find each other over networks. What's next?
Getting Started
When you write a DB program, you have the option of creating a separate program from the game (a server) which runs on a machine connected to your network (or the internet). Your game would then allow you to connect to this server which passes all the data round to all those connected to it. This is your basic 'Quake Server' option.
Alternatively, you can put the server side of things in the game program so one of the players decides to be host and all the others connect onto him or her, by adding that option into the game. For simplicity, we'll assume that we are going to be writing separate programs for server and client.
The first thing we need to do is create our server, so that's where we'll start.
Choose Your Connection
DB's Multiplayer options don't just work with TCP/IP through a router via the internet. You can also connect two machines via a serial cable, dial via a modem or run the server and client on the SAME machine. These are all different types of Connection and you have to choose which one you are going to use from those available. That's where Perform Checklist For Net Connections comes in.
This will return a numbered list of what connections are available on your machine. As with all of DB's Perform Checklist calls, the number of items found is stored in checklist quantity() and the actual items stored in Checklist String$(N) where N is the item number. So we add the following to our program:
Perform Checklist For Net Connections
NumConnections = checklist quantity()
For N=1 to NumConnections
If Upper$(Left$(Checklist String$(N),8))="INTERNET"
NetConNumber = N
Exit
Endif
Next N
Set Net Connection NetConNumber,"192.168.1.2"
For the purpose of this tutorial, Our game server only needs to support Internet and Local Area Network - both of which use the TCP/IP option. If you need to use one of the other options, I'm sure that this tutorial when completed will have given you enough knowledge to alter your own code to suit your needs.
Anyway, the above code checks for Net Connections and we use the variable NumConnections to store the number found.
On my machine, I get 3 options, the third of which is 'Internet TCP/IP Connection For DirectPlay'. The other two are for serial connection and modem.
So, in our program we run through a loop grabbing the first eight characters from the options returned and make them upper case. If the result is the word "INTERNET", then we know that N equals the number of the TCP/IP option, so we save the value of N in NetConNumber and jump out of the loop.
Using the value now stored in NetConNumber we can now try opening a connection to receive logins from other people. The only other thing it needs is an IP address. This same command is also used when opening an outgoing connection where the IP address of the machine you want to connect to has to be supplied. With a server application, it's an incoming connection we are establishing, so there is no remote IP address to supply. So we simply enter the IP address of the machine it's running on - in my case, 192.168.1.2.
If you use "" instead of an IP address the program will pop up a windows dialog asking you to enter the required IP address. You can enter the machine's IP address there or just press Enter to ignore it.
Providing there are no errors, we can safely assume that an open connection has been established so it's onto the next stage - creating a net game...
Create Net Game
At this point in coding our multiplayer program we have the option of creating Peer To Peer (P2P) links between all the players where all are connected to each other for transferring data, or a client/server system where users all log into the server and the server distributes the data around to all the players. We are going to be using the client/server option in this tutorial.
So I used the following code:
Create Net Game "TDKServer","TDK_Man",10,2
Ink RGB(0,255,0),0
If Net Game Exists() = 1
Center Text 320,20, "Server Successfully Started!"
Else
Center Text 320,20, "Sorry - Unable To Start Server Session!"
End
Endif
Create Net Game has four parameters. The first is the session name. This is what the user at the other end will see when they try to connect. The second is the 'owner' of the connection and is in effect your username which others will see in the game itself.
The next parameter (10) is the number of people you are allowing to connect to the server (the maximum number allowed to play the game). You can have up to 255 connections, but if you are using a machine at home, your net connection may well buckle under the strain, so this is where you relieve the pressure. You may even have a game where only four people can play, so in such a case you would use 4 for this parameter.
Also, don't forget that the server uses up one of those 10 slots...
The last number is a flag for the options I mentioned earlier. If you want P2P connections, put a 1 here. If you want a stand-alone game server, put a 2. In this example, we need a 2.
Net Game Exists() is simply a test to see if the game we just tried to start is actually running. If a 1 is returned, then it is. If a 0 (zero) is returned, then we can print a suitable message and end the program as nothing is going to work if this fails anyway.
Assuming all has gone to plan, we should now have a net game running and waiting for someone to connect!
Messages
Everything revolves around messages that are received from the players connected to the server and those that the server sends out to the players. Messages can be in a variety of formats.
You can send a number of message types, though the most commonly used ones are going to be string, integer and float variables.
For example, if six people are driving around a race track, the server is going to have to receive information from all the players - like each player's positions on the circuit and then send it all back out to all the other players so that all copies of the game draw the other players cars in the correct positions.
In it's simplest form, this could be done by sending just the X and Z position for each player's car, though you'll probably want to send other information too. And yes, you can even program the Function keys to send taunts to your opponents just before you blow their heads off!
Incoming Messages
Our server is mainly concerned with distribution of messages, so it needs to receive them first. This is done with Get Net Message.
Like with Net Game Exists(), there is also Net Message Exists() to test if there is a message in the queue waiting to be processed.
Each message received is best thought of as a 'package' which contains various bits of information. There is a command to extract each piece of information so you can process each message. These are:
Net Message Type() - This returns an integer and the three common message types have already been mentioned - Integer, real and string. There are other less commonly used types like Memblock, Bitmap, Image, Mesh and Sound, but they are outside the scope of this tutorial and you can look them up yourself in the help files if you need them.
The ones we are going to use are as follows:
Integer: Net Message Type() returns a 1. Actual integer value is stored in Net Message Integer().
Float : Net Message Type() returns a 2. Actual float value is stored in Net Message Float().
String : Net Message Type() returns a 3. Actual string value is stored in Net Message String$().
Other associated message commands are:
Net Message Player From()
This returns the player number the message was received from. The player who initiates the server is player 1 and is always part of the game, appearing on the list of players logged on.
Net Message Player To()
This is the same as Player From(), but returns the number of the player that the message was aimed at. For example, in a game, it's possible for a couple of players to team up and this option gives them the opportunity to send private messages between themselves.
So, having found that a message has arrived, these commands can be used to find out who the message is from, who it's being sent to and what sort of data is in the message. A simple Select..EndSelect structure can be used to decide how to process the message.
If Net Game Exists() = 1
Get Net Message
While Net Message Exists()=1
MsgType = Net Message Type()
MsgFrom = Net Message Player From()
MsgTo = Net Message Player To()
Rem Build string Packet$ to write to screen...
Packet$ = " From: " + Str$(MsgFrom)
Packet$ = Packet$ + " To: " + Str$(MsgTo)
Packet$ = Packet$ + " Data: " + Str$(MsgType)
Select MsgType
Case 1
Packet$ = Packet$ + " Integer: " + Str$(Net Message Integer())
EndCase
Case 2
Packet$ = Packet$ + " Real: " + Str$(Net Message Float())
EndCase
Case 3
Packet$ = Packet$ + " String: " + Net Message String$()
EndCase
EndSelect
Connections$(MsgFrom) = Packet$
Rem Check for other events here...
Get Net Message
endwhile
Endif
In this example, a string called Packet$ is built up with the information received in the message and can be printed to the screen if required.
When Did They Connect?
When someone does connect, a message event is triggered, and the fact that a new player has been created is recorded. So, somewhere in the While Net Message Exists()=1 loop, we need to check to see if the current message was raised because this has happened. (I've left a blank line in the block of code above to show you where it would be inserted). This is done with:
PlayerNum = Net Player Created()
If PlayerNum > 0
cls 0
Print
print "New Player Logged In: ";PlayerNum
endif
At this point, although we have the number of the new player, the program at the other end which has just connected to the server doesn't know what it is as it doesn't yet know how many other players are currently connected. So, what we do is send this number back to the user in a message. It could be something as simple as "Welcome! You are now player 3 connected to the Pong server.".
We'll cover that later though in the section on Outgoing Messages...
What If The Connection Is Lost?
Once again, a message event is fired and we need to have a little test to check if the current message is due to this happening. For this, we use Net Game Lost()...
If Net Game Lost()=1
Center Text 320,60,"Session Lost!"
Sync
Endif
This is not if the server loses contact with one of the players, this is when the server's net connection goes down and the server loses contact with everybody!
Where Did They Go?
If someone disappears, be it due to your carefully crafted game going belly up with a 'File Not Found' error, or someone's been given their last warning to get down those stairs and get their dinner before it goes cold, a player disappearing raises a message event. This is checked for with Net Player Destroyed():
PlayerNum = Net Player Destroyed()
If PlayerNum > 0
Cls 0
Print
Print "Player Logged Out: ";PlayerNum
Endif
Who's Currently Connected?
At any time, you can use Perform Checklist For Net Players to find out who's currently logged on:
Perform Checklist For Net Players
If Checklist Quantity() > 0
Name$ = ""
For N = 1 To Checklist Quantity()
Name$ = Name$ + Checklist string$(N)+" "
Next p
Ink RGB(255,0,255),0: Text 10,450,Name$
Endif
This puts a list of names at the bottom of the screen in a similar way to how the list of members logged onto the forums appears at the bottom of the main DB forums page.
OK, that's about it for incoming messages, so now we'll take a look at how we get our server to send messages back to the players:
Outgoing Messages
First of all, it's assumed that you are connected and have a net game running for the following to work. Just thought I'd better point that out...
Sending a message is simply a case of calling the correct Send Net Message. Which one you use depends on the type of data packet you want to send. You have the following common data types:
Send Net Message Integer 3,Count
...Which would send the contents of the integer variable 'Count' to player number 3.
If you use 0 (zero) then the message is sent to all players, but not yourself naturally, so:
Send Net Message Float 0,Player1XPos#
...would send the contents of float variable Player1XPos# to ALL players.
Send Net Message String 2,Taunt1$
...would send the string Taunt1$ to player 2.
That's all there is to it.
When the message is received at the other end, the client program uses basically the same system as described above to decide what to do based on the messages it receives. The only difference being that whereas the server program has to receive and distribute messages that it receives to one or all of the clients, the client only has to talk to the server.
This tutorial only includes snippets of code taken from my rough but working server program - to explain what to do. When Tutorial 2 is complete, I will finish off the client and server programs, make them tidy and presentable and make the source code available to download.
Next, Part II - writing the client!
There are many more tutorials and example code snippets on TGPF - my game programming forums. Click on the link below - it's free to join and everyone's welcome!
Visit TGPF
TDK_Man August 2005