Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9
      Miscellaneous

DirectXPlay: Client-Server
Author: Almar Joling
Written: 12th July 2001
Contact:
[Web site] [Email]
Download: DP_Sample.Zip (34kb)


Contents of this lesson
1. What we are going to make
2. Client basics
3. Server basics


1. What we are going to make

The game we are going to make is not the type of game you'd probably love to see. No Subspace, no Quake3. This game will be much more intense and mind-struggling. I know you're all wanting such code, but it seems that multiplayer code is very rarely available, and if you find out which tricks where used to compensate lag and packet-loss, you'll have to be killed by the large companies (At least, that's what I experienced, except for the killing part). Our game will be Tic Tac Toe. Yep, I bet you always wanted to play that online :o)
Now back to the serious business. The game we are going to make is Tic Tac Toe. Even if you might find the code of this game simple, it can't be compared to any code in real-time action games. We don't care about lag in Tic-Tac-Toe. And we don't have to care about packet loss because we will send the data guarenteed anyway, because we don't have to send a packet every 200ms. I've tried to make this client-server as easy understandable as possible. I'm not going to "enumerate" sessions; still haven't looked how to do it :o). Maybe I'll add that later anyway.

Our game will simply be built up of command buttons for the "O", and "X"'s and we'll use a textbox for our chat function in our game. What's a tic tac toe game where you can't laugh at your losing opponent? Exactly. I'm writing this tutorial for people that have some experience in VB, and have a bit of an idea what multiplayer gaming is. I've seen and have been asked by many people to help in multiplayer programming. And there are lots of them who can barely use VB. The chance that the game will be finished is minimal. Read the note below, and re-read it a few times. Maybe I'll add some interesting links at the end of the tutorial that might help in developing your multiplayer game.

Note: Multiplayer programming is hard, know what you're getting into! It might seem so simple but it isn't.

 


2. Client basics

In case you skipped my previous article, or just forgot to read a sentence: Client/server means that every client sents the data to the server which will route it to other players accordingly to the programmed code.
So let's first get working on the Client side of our Tic Tac Toe game. Please note that I'm not going to put every line of code in here. So copy and paste won't work. You can download the complete tutorial above.

'//We'll need the following declarations:
Option Explicit
Public objDPClient As DirectPlay8Client	    '//This is the most important part 
Public objDPAddress As DirectPlay8Address   '//Will be used for the IP address later
Public objDX8 As DirectX8		    '//DirectX object.

 

For Tic-Tac-Toe, Client/Server is somewhat an wrong connection method. There aren't going to be more than two players in the game anyways. with Peer-Peer every one receives notification when someone leaves the game, or joins the game. with Client/Server it doesn't come nearly as close to make it this easy. Only the server receives the join/leave events, so the server should broadcast this to all other (active) players. The server has the responsibility for the entire game. to be honest, I had some trouble creating the Tic-Tac-Toe Client/Server game, since I'm used to realtime multiplayer programming (Quadrant wars) instead of turn based. I've rewriten it two times, and the second version used half the code. Rewriting your multiplayer game is often an essential part, where you can solve minor problems and optimise your code.

Public Const AppGuid = "{5726CF1F-702B-5008-28BC-EF9C95D9E288}"
Public Const intServerPort As Integer = 4000 '//Use 4000 as serverport (we'll connect to that port)

 

The code above demonstrates the Application GUID. This is an unique ID for the client and the server. If the client or the server do not have the same ID, they can never connect to each other. It's very handy when new versions of client and servers are released. Changing the GUID to something else will make all other clients obsolete (unless there are still old servers online). The ServerPort is the port where we are going to connect to on the server. The server has the same port to listen on. When choosing ports, it's generally recommended that you choose ports above 3000. If you choose lower you might try to listen on ports used by proxies, firewalls, or something else. Now we have all the declarations to get DirectPlay8 going.

 

Set ObjDX8 = New DirectX8
Set ObjDPClient = ObjDX8.DirectPlayClientCreate              '//Create DP Client
Set ObjDPClientAddress = ObjDX8.DirectPlayAddressCreate      '//Create Client DP address
Set ObjDPServerAddress = ObjDX8.DirectPlayAddressCreate      '//Create Server DP address
ObjDPClient.RegisterMessageHandler frmMain                   '//Register Server message handler, our form!
ObjDPClientAddress.SetSP DP8SP_TCPIP                         '//Configure Client address for TCP/IP
ObjDPServerAddress.SetSP DP8SP_TCPIP                         '//'Configure Server address for TCP/IP
ObjDPServerAddress.AddComponentLong DPN_KEY_PORT, intServerPort '//Add the serverport to the ServerAddress

The code aboves creates the DirectX8 object, DP8 Client object, and two DirectPlayAddresses. We'll need those two later to connect to our server. We set one Address (Client) to our local IP, and one to the destination, server IP. Here we also register the message handler. From this point we receive every event fired by DirectPlay8. Don't forget to add all the events to your form, or you'll get an "Type mismatch" error. The "DP8SP_TCPIP" tells DirectPlay to use the TCP/IP protocol, for network/internet usage. If you specify these directly, you do not have to enumerate the service providers anymore, for example modem, serial connection, IPX, etc. The AddComponentLong can be used to set several properties for the connection. Here we only add the port that we use for our game.
To simplify the client connection code, I've removed the part that asks for the hostname/IP. check the source for this.

 

Dim AppDesc As DPN_APPLICATION_DESC '//Application description
    
ObjDPServerAddress.AddComponentString DPN_KEY_HOSTNAME, strHostName '//Add this remote host to the server connection address
AppDesc.guidApplication = AppGuid   '//This is a Guid, to indentify all your clients (for enumeration)
     
        
'//If we are connected a "connect complete" event will trigger in frmClient
ObjDPClient.Connect AppDesc, ObjDPServerAddress, ObjDPClientAddress, 0, strPlayerName, Len(strPlayerName)

 

You can seen another "AddComponentString". This time we add the hostname or IP address of the server. We'll connect to that address using "ObjDPClient.Connect".
Writing this tutorial learned me something new. An easy method to send a playername while connecting to the server! Normally this would involve being connected already, and then after a few packets finally commence gameplay.

 

Dim PlayerInfo As DPN_PLAYER_INFO
'//Set up peer info
PlayerInfo.Name = InputBox$("Playername?", "Playername", "Myself")
strPlayerName = PlayerInfo.Name
PlayerInfo.lInfoFlags = DPNINFO_NAME
ObjDPClient.SetClientInfo PlayerInfo, DPNOP_SYNC

 

This will simply add the specified name to the client, and can be retrieved serverside using GetClientInfo.
After connecting an "connect_complete" event will be fired. You can here notify the user that a connection has successfully been made.

That's all for the client side. Sending/Receiving has already been covered on the previous page.

 


3. Server basics

The server of this game doesn't do very much. It's often better to do the most CPU intensive calculations on the clients, instead of the server. This way you can have much more players while the server doesn't go into overkill mode, becoming slow because certain actions have to be performed. When a server has to loop every 1\10 of a second through an array of 500 players, latency will occur, and it isn't caused by your internet connection, but simply the processing time of your server.
But since I wanted to show some server side game handling, I've made it so that the server checks if the game was won by someone or if the game became a tie. You could compare this to server side cheat protection. If I would do this on the client side, it would be easier to make changes to the game (using packetsniffers or an hex editor) and let other clients know player xx won.

Private Const AppGuid = "{5726CF1F-702B-5008-28BC-EF9C95D9E288}"
Private Const intServerPort As Integer = 4000    '//Use 4000 as serverport (we'll listen on that port)

Public objDX As DirectX8                        '//Main DirectX8 object
Public objDPServer As DirectPlay8Server         '//Server object, for message handling
Public objDPServerAddress As DirectPlay8Address '//Server's own IP, port

 

You can see that the first two lines are identical to the variables used by the client. The Appguid and serverport need to be identical for the client and server to see each other. The DX8 object is also present again. But instead of having a DirectPlay8Client object, we have an DirectPlay8Server object, that will be used for our server. The serveraddress is used for listening on the local IP, and to set the TCP/IP provider.

 

Dim AppDesc As DPN_APPLICATION_DESC     '//Application description
With AppDesc
    .guidApplication = AppGuid          '//Same as client! (Important!)
    .lMaxPlayers = 3                    '//TicTactoe = max 2 players + 1 server
    .SessionName = "TicTacToe Game"     '//Name our session like this
    .lFlags = DPNSESSION_CLIENT_SERVER  '//this game is 100% Client-Server
End With
                
Set objDX = New DirectX8                                    '//Create DirectX object
Set objDPServer = objDX.DirectPlayServerCreate              '//Create Server object
Set objDPServerAddress = objDX.DirectPlayAddressCreate      '//Create Server DP address
objDPServer.RegisterMessageHandler frmMain                  '//Register Server message handler
objDPServerAddress.SetSP DP8SP_TCPIP                        '//Configure Server address for TCP/IP
objDPServerAddress.AddComponentLong DPN_KEY_PORT, intServerPort '//Listen on this port
objDPServer.Host AppDesc, objDPServerAddress                '//Start hosting the session

 

The code above starts the server. We give the Application description the guid, and the number of players. Remember, the server is also a player. if you want your game limited to 16 players, it has to be 17! We also specify the session name, which will be visible if we enumerate sessions (what we won't do here in this game) and specify the flag that tells DirectPlay that this game will be client-server. There are lots of flags available, and I recommend you to read those in the DX8 SDK docs.
Like for the client, we again create a DirectX object, a Server object and an address object. The Server object will again use an event handler, so do not forget to add all events to the form. We set the service provider to TCP/IP, so this game can run on networks and Internet. Further we add the serverport again, just like the client side code. When calling "Host" the server will start and also be available for clients to join!

That is practically everything you need to know to get a server running, but there are a few things I'd like to explain. When you call Host, the server will be started. If this succeeds a "CreatePlayer" event will be fired. So, the first server CreatePlayer event is always the playerid of the server! Don't forget that one.

It is also possible to forwards packets directly, by just passing the "dpnotify.receiveddata" to the "DPServer.SendTo" method, but it seems that it doesn't like to work on my PC, while it worked before. It does work in someone else his game. I've copied his code but it still didn't work. I'm not sure if this might be caused by a difference in DX8a and DX8, and Microsoft doesn't seem to know it either. (Someone from Microsoft said it should work, but he lacked VB, so he didn't know it for sure)

You can download the complete, working source code from the top of the page, or from the downloads page.

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster