Initial commit: ROW Client source code

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>
This commit is contained in:
2025-11-29 16:24:34 +09:00
commit e067522598
5135 changed files with 1745744 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
//-----------------------------------------------------------------------------
//
// 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.