Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
127 lines
6.5 KiB
Plaintext
127 lines
6.5 KiB
Plaintext
//-----------------------------------------------------------------------------
|
|
//
|
|
// Sample Name: DataRelay Sample
|
|
//
|
|
// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
Description
|
|
===========
|
|
The DataRelay is similar to SimplePeer but differs by sending a single
|
|
target (or everyone) a packet of data with options specified in the
|
|
dialog's UI. It uses a worker thread to process received data, and
|
|
uses the ReturnBuffer() API so that no copying of the received buffers
|
|
is done.
|
|
|
|
Path
|
|
====
|
|
Source: DXSDK\Samples\Multimedia\DirectPlay\DataRelay
|
|
|
|
Executable: DXSDK\Samples\Multimedia\DirectPlay\Bin
|
|
|
|
User's Guide
|
|
============
|
|
Host or connect to a session in the same manner as explained in SimplePeer.
|
|
When the main dialog appears select the target, size, rate, and timeout values.
|
|
Then click "Push to Send". This will send a packet of data to the target as
|
|
the rate specified with the specified size. Use the "Connection Info" dropdown
|
|
to specify a target to gather connection info on periodically.
|
|
|
|
Programming Notes
|
|
=================
|
|
The DataRelay sample is very similar in form to the SimplePeer sample. For
|
|
detailed programming notes on the basics this sample, refer to Programming
|
|
Notes section of the SimplePeer sample.
|
|
|
|
The DataRelay differs by sending a single target (or everyone) a packet of
|
|
data with options specified in the dialog's UI.
|
|
|
|
When the "Push to Send" button is clicked, then win32 timer is created
|
|
that goes off every number of ms according to the UI.
|
|
|
|
* Upon the WM_TIMER labeled TIMERID_NETWORK, it calls SendNetworkData().
|
|
1. It creates a app defined struct, GAMEMSG_DATA_xxx on the heap.
|
|
The struct derives from GAMEMSG_GENERIC. GAMEMSG_GENERIC contains a
|
|
packet type field so that the reciever and identify this app defined
|
|
packet, and it contains a packet ID field. This field is sequential
|
|
and is displayed to the user whenever a packet is received. The struct
|
|
is created on the heap, since will use the DPNSEND_NOCOPY when calling
|
|
SendTo() below. The struct is filled with random data, however a real
|
|
app would typically send player and world state data here.
|
|
2. It then creates a GAMEMSG_DATA_NODE which is then handed off to the
|
|
app worker thread. That thread will process the node, and
|
|
then update the UI to show that a packet was sent. It is handed off
|
|
by adding the node to a linked list. Since the worker thread also
|
|
accesses the linked list, we enter a critical section before adding the
|
|
node and leave it afterward.
|
|
3. A DPN_BUFFER_DESC is then filled out passing in a pointer to the
|
|
app defined struct created above.
|
|
4. IDirectPlay8Peer::SendTo is called passing in the DPN_BUFFER_DESC, thereby
|
|
sending the app defined struct, GAMEMSG_DATA_xxx. We call SendTo with
|
|
the flags DPNSEND_NOLOOPBACK | DPNSEND_NOCOPY. DPNSEND_NOLOOPBACK tells
|
|
DirectPlay to not to send the buffer to us, and DPNSEND_NOCOPY means that
|
|
DirectPlay should not copy the buffer. When the DPNSEND_NOCOPY is used,
|
|
the app itself owns the buffer, and the buffer must be on the heap.
|
|
When the DPN_MSGID_SEND_COMPLETE comes in, we will delete the buffer.
|
|
5. The event, g_hDPDataAvailEvent, is set telling the worker thread that
|
|
there is data (a message to say that a packet was sent), is ready to
|
|
be processed now.
|
|
|
|
* Handle DirectPlay system messages. See DirectPlayMessageHandler()
|
|
The DataRelay handles the typical messages as described in the
|
|
SimplePeer programming notes, and in addition:
|
|
|
|
- Upon DPN_MSGID_RECEIVE
|
|
1. It casts the pReceiveMsg->pReceiveData to a GAMEMSG_GENERIC*.
|
|
2. It then switches off the GAMEMSG_GENERIC's dwType.
|
|
3. If its a GAME_MSGID_GAMEPACKET, then it creates and fills out
|
|
a GAMEMSG_DATA_NODE. This node is then handed to a worker thread
|
|
so it can be processed outside of the DirectPlay message handler.
|
|
This is important since it keeps the DirectPlay threads working at
|
|
full speed.
|
|
4. After the node is added to the linked list using a critical section
|
|
to lock, it returns DPNSUCCESS_PENDING. This is important since
|
|
it tells DirectPlay that ownership of the buffer
|
|
has been transferred to the application, and so DirectPlay will
|
|
neither free nor modify it until ownership is returned
|
|
to DirectPlay through the ReturnBuffer() call.
|
|
|
|
- Upon DPN_MSGID_SEND_COMPLETE
|
|
1. It checks the pSendCompleteMsg->hResultCode for DPNERR_TIMEDOUT.
|
|
2. If this occurs then it creates a new GAMEMSG_DATA_NODE with dwType
|
|
set to DATA_TYPE_NETPACKET_TIMEOUT. This will is passed to the
|
|
worker thread. The worker thread will process this node, and
|
|
post a message to the dialog saying that the message timed out.
|
|
A realistic application would want to take the appropriate steps here,
|
|
such as resending new data or other measures.
|
|
3. It deletes the buffer from the heap since we specified, DPNSEND_NOCOPY,
|
|
so the buffer on the heap belows the app and it must clean it up.
|
|
|
|
* The worker thread. See ProcessNetDataProc()
|
|
- Upon the g_hDPDataAvailEvent
|
|
1. When the event is signaled, then new data can be found in the
|
|
linked list, g_DataHead. So it calls ProcessData().
|
|
2. ProcessData() first enters the critical section, g_csDataList, so
|
|
that the other threads don't modify the linked list while it is
|
|
processing data. It leaves this critical section at the end of the
|
|
loop. Typically better locking mechanisms would be used so that the
|
|
other threads (as well as the DirectPlay message handler threads)
|
|
aren't blocked while data is processed on this thread.
|
|
3. It runs through the linked list, processing each node. For this
|
|
simple sample all it does is posting a message to the dialog thread,
|
|
containing a string for the dialog to display.
|
|
4. After it is done processing the node, it calls
|
|
IDirectPlay8Peer::ReturnBuffer() so that DirectPlay can free
|
|
buffer that it passed us in DPN_MSGID_RECEIVE.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|