Advertisement

Does anyone here know how to use DirectPlay?

Started by May 08, 2005 09:20 AM
18 comments, last by hplus0603 19 years, 9 months ago
Yes, I think you're right. I haven't used locks too much, but just one question, where is it most appropriate to use critical sections?

A problem seems to happen in the client program in the Connect() function, and all of its parameters have been set up correctly... After the client receives the DPN_MSGID_CONNECT_COMPLETE message. I know that the error occurs before the Connect() function completes, because immediately after the function, I have debug output. I set an event to show when the connection has been completed, and it relies on the WM_TIMER message.

case DPN_MSGID_CONNECT_COMPLETE:		#ifdef RENDER_DEBUG		MessageBox( 0, "DirectPlayMessageHandler: DPN_MSGID_CONNECT_COMPLETE", "Client Message", 0 );		#endif		PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;		pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;		MessageBox( 0, "ENTER CRITSECTION - DirectPlayMessageHandler: DPN_MSGID_CONNECT_COMPLETE", "Client Message", 0 );		// An error is caused here unless the following line is commented		// I'm not sure why this occurs, because this critical section can be used without		// errors in other cases.		EnterCriticalSection( &g_csMessageSection );				MessageBox( 0, "DONE CRITSECTION - DirectPlayMessageHandler: DPN_MSGID_CONNECT_COMPLETE", "Client Message", 0 );		//#ifdef RENDER_DEBUG		MessageBox( 0, "DirectPlayMessageHandler: DPN_MSGID_CONNECT_COMPLETE", "Client Message", 0 );		//#endif		g_hrConnectComplete = pConnectCompleteMsg->hResultCode;		SetEvent( g_hConnectCompleteEvent );				//#ifdef RENDER_DEBUG		MessageBox( 0, "g_hConnectCompleteEvent set", "Client Message", 0 );		//#endif		LeaveCriticalSection( &g_csMessageSection );		//#ifdef RENDER_DEBUG		MessageBox( 0, "DirectPlayMessageHandler: DPN_MSGID_CONNECT_COMPLETE Completed", "Client Message", 0 );		//#endif		break;


There isn't any important code within this function after the break at the bottom of the source code.

The final message box is shown, but an error occurs immediately after the message handler returns its value. This means it crashes before the Connect() function completes, even though it says that the connection has been completed.
If you are using the default settings, DirectPlay creates a thread pool that will call your callback function whenever a message need to be processed. You are unwillingly dealing with a multi-threaded app now and MT apps have peculiar behaviours you need to watch for.

> I set an event to show when the connection has been
> completed, and it relies on the WM_TIMER message

You are using DPNCONNECT_SYNC in the Connect() call, hence the main thread will be waiting there until either you connect or an error has occured. In the mean time, the callback function will process a slew of secondary messages coming from the DirectPlay thread pool. You should refrain from doing anything graphics in those threads (this includes MessageBox()). You can have something like:

EnterCriticalSection(..);
OutputDebugString(...);
LeaveCriticalSection(..);

packaged in a function for all your debug output. This will be send to the debugging output window without requiring any thread-specific context.

-cb
Advertisement
Okay, thanks for that! I always find that when I fix one bug, another comes along, though...

When the Connect() function should have completed, and the DPN_MSGID_CONNECT_COMPLETE message has been sent and all of the processing associated with that message has been completed, it then crashes. It doesn't even leave the Connect() function. What happens after the DPN_MSGID_CONNECT_COMPLETE message is sent?
You should be getting a slew of DPN_MSGID_CREATE_PLAYER messages corresponding to all the nodes that are connected. You should examine the dwPlayerFlags data member to see if the bit DPNPLAYER_LOCAL is set or not. If set, this is the local instance otherwise it's either the server in C/S mode or all the other nodes in Peer mode.

-cb
Alright, that problem has been fixed, but I found another one. :D Hooray. What does it mean when the program crashes when I call the EnterCriticalSection() function? Does it mean that that thread is already in use and when another function tries to access that thread, it crashes? I thought it would wait until the thread was unlocked. I find that this occurs only some of the times I try to enter the critical section.

What I'm trying to do now is render to screen (which was working perfectly before I implemented networking), but it seems that the programs crashes when I attempt to do any operations with the back buffer. Is it because I haven't exited a critical section before doing the operations? I programmed rendering to screen to be a completely separate function from any networking functions.

Edit: The above problem, I believe, is unrelated to DirectPlay, as DDraw is set up before DPlay, and the first error occurs in setting up DDraw. Odd.

[Edited by - Reinhart on May 11, 2005 11:26:46 AM]
Quote:
Original post by Reinhart
Alright, that problem has been fixed, but I found another one. :D Hooray. What does it mean when the program crashes when I call the EnterCriticalSection() function? Does it mean that that thread is already in use and when another function tries to access that thread, it crashes? I thought it would wait until the thread was unlocked. I find that this occurs only some of the times I try to enter the critical section.

What I'm trying to do now is render to screen (which was working perfectly before I implemented networking), but it seems that the programs crashes when I attempt to do any operations with the back buffer. Is it because I haven't exited a critical section before doing the operations? I programmed rendering to screen to be a completely separate function from any networking functions.

Edit: The above problem, I believe, is unrelated to DirectPlay, as DDraw is set up before DPlay, and the first error occurs in setting up DDraw. Odd.


Are you using the address of your CRITICAL_SECTION variable?

ie.
CRITICAL_SECTION g_cs;InitializeCriticalSection( &g_cs );//then lock/unlockEnterCriticalSection( &g_cs );//blah!LeaveCriticalSection( &g_cs );//cleanupDeleteCriticalSection( &g_cs );


Make sure those critical section blocks are SHORT and sw33t. Definitely don't leave it locked then do other things, etc..
Learn about game programming!Games Programming in C++: Start to Finish
Advertisement
Alright. :) Yeah, I use references in all of them.

All problems fixed so far. :D Now I came across another problem when sending messages from the client to the server. All I want to do is send a chat packet, and from there I can send any kind of information.

In the server program, the DPNID which is saved when I create my player is different from the DPNID supplied when I receive a message. Can the DPNID change like that? I thought it would remain the same as long as the client stayed connected.

Edit: Checking my Create Player function, even when the server creates itself, it provides a different DPNID from its local DPNID. O_o Can anyone help?

For example:

sprintf( temp, "Msg DPNID: %d", &(pCreatePlayerMsg->dpnidPlayer) );MessageBox( 0, temp, "Server: hrCreatePlayer Msg DPNID", 0 );

That displays the DPNID supplied by the packet. It comes out as something like 13575277.

sprintf( temp, "Local DPNID: %d", &(g_dpnidLocalPlayer) );MessageBox( 0, temp, "Server: hrCreatePlayer Local DPNID", 0 );

That displays the local DPNID of the server, which is something like 7769295. :S

[Edited by - Reinhart on May 12, 2005 12:00:24 PM]
I'd point you to the DPlay samples that come with the 8.1 SDK...they show the basics of all of that stuff..

hth,
Learn about game programming!Games Programming in C++: Start to Finish
Okay, I'm really stuck with DPNIDs. :( They always seem to send the wrong DPNID, and I'm not sure I can see how the samples help. MSDN doesn't even have a page explaining DPNIDs. Why would the DPNIDs change?
You're printing the address of your dpnids, not the dpnids themselves. Of course the addresses where they're stored may change between invocations (when they're on the heap).

If you had used a type-safe printing function, like cout, this bug would have been caught by the compiler. Also, some compilers with warnings turned off will tell you about printing pointers as ints.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement