|Microsoft DirectX 9.0|
Most applications will want to associate some data with each player. However, when you receive a message that is associated to a player, you need some way to access that data quickly. Player context values are designed to provide you with an efficient way to access your player data.
To user player context values, you need to have a block of data on your system for each player, typically in the form of a structure. A player context value is normally an index into an array of pointers to the various players' data blocks. When you receive a message from a player, there is no need for time-consuming operations such as searching for the player's identifier (ID) in a table. The index contained in the player context value allows you to quickly obtain the necessary pointer.
You define a player context value when you handle the DPN_MSGID_CREATE_PLAYER message that notifies you that a player has been added to the game. Host's can also define a player context value when they handle the DPN_MSGID_INDICATE_CONNECT message. That player context value will be set in the subsequent DPN_MSGID_CREATE_PLAYER message. When the host processes that message, it has the option of changing the player context value. To create a player context value:
Microsoft?DirectPlay?does not specify how you should obtain the data to populate the structure. Each game is responsible for handling that issue in its own way.
While player context values are fairly straightforward to handle, there are a couple of issues that you need to be careful with.
The player context value provides you with a quick way to obtain a valid memory address that will presumably be accessed each time a message arrives. However, you must be careful that different parts of your application do not access the data at the same time. DirectPlay serializes messages associated with a particular player, which guarantees that you will never be handling two messages from the same player at the same time. As long as you only access the data structure from your callback message handler, you can safely access the structure. However, most applications will need to access player data outside the message handler.
If your application accesses the data outside the callback message handler, you must prevent concurrent access by providing some sort of global mechanism to lock the structure. Even if your application does not require such locking in the early stages of development, you should assume that locking will eventually be required, and build it in from the beginning. If your player context values that are indexes into an array, you should also make sure that you read and update that array safely.
Don't deallocate a player's data structure prematurely. When a player leaves the game, you will normally want to deallocate their data structure and free the associated memory. However, be careful about deallocating the structure as soon as you receive a DPN_MSGID_DESTROY_PLAYER message. If your application accesses that structure outside the callback message handler, that data may still be in use when the message arrives. If you deallocate the structure as soon as the message arrives, you may cause other parts of your application to fail.
To avoid prematurely deallocating the structure, you should not only provide an application-level locking mechanism, you should also implement some sort of reference counting. Increment this reference count when you create the structure, and every time you use it. Decrement the reference count every time you have finished with the structure, including in your DPN_MSGID_DESTROY_PLAYER message handler. As long as the reference count is nonzero, some part of your application is accessing the structure. Do not deallocate the structure until the reference count drops to zero.