DirectPlay system messages#
Summary#
DirectPlay delivers system traffic from player id 0. Lords of the Realm 2
reads the first DWORD of the receive buffer as dwType and routes every
DirectPlay 3 DPSYS_* message it recognizes to lotr2_net_handle_system_message.
All claims here are inferred from client code unless otherwise noted.
Evidence#
| Claim | Level |
|---|---|
System messages arrive with sender id 0 |
inferred from client code |
dwType is read from receive buffer offset 0x00 |
inferred from client code |
Eight DPSYS_* values are routed |
inferred from client code |
Fields after dwType use stock DirectPlay 3 SDK layouts |
inferred from SDK layout; not verified on wire |
Session Context#
System messages are processed inside lotr2_net_poll_messages after
IDirectPlay3::Receive fills the shared receive buffer at DAT_0052d490.
Messages from lotr2_net_local_player_id are treated as self-echoes and
ignored. Messages from any other nonzero sender are custom app frames; see
dplay-app-messages.md.
Message Routing#
dwType |
DirectPlay constant | Internal index | Client action |
|---|---|---|---|
0x00000003 |
DPSYS_CREATEPLAYERORGROUP |
1 | Logs create; reads created DPID from DAT_0052d498. |
0x00000005 |
DPSYS_DESTROYPLAYERORGROUP |
2 | Removes slot; before gameplay, broadcasts app opcode 3 roster sync. |
0x00000007 |
DPSYS_ADDPLAYERTOGROUP |
5 | Logs only. |
0x00000021 |
DPSYS_DELETEPLAYERFROMGROUP |
6 | Logs only. |
0x00000031 |
DPSYS_SESSIONLOST |
3 | Logs session lost. |
0x00000101 |
DPSYS_HOST |
4 | Logs host migration and sets lotr2_net_is_host = 1. |
0x00000102 |
DPSYS_SETPLAYERORGROUPDATA |
7 | Logs only. |
0x00000103 |
DPSYS_SETPLAYERORGROUPNAME |
8 | Logs only. |
Generic Field Layouts#
DirectPlay system messages are standard DirectPlay payloads, not the custom
lotr2_net_msg_header frame. The client only reads dwType in the receive loop
and, for create/destroy, the DPID at offset 0x08.
DPSYS_CREATEPLAYERORGROUP (0x00000003)#
SDK payload: DPMSG_CREATEPLAYERORGROUP.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_CREATEPLAYERORGROUP. |
dpId |
0x04 | 4 | uint32le | Created player or group id. |
dwPlayerType |
0x08 | 4 | uint32le | DirectPlay player/group type. |
lpData |
0x0c | 4 | pointer | Player data pointer in local process. |
dwDataSize |
0x10 | 4 | uint32le | Player data byte count. |
dpnName |
0x14 | 16 | DPNAME | DirectPlay name structure. |
- Direction: DirectPlay system -> client.
- Trigger: another player or group is created in the session.
- Handler (parse):
lotr2_net_handle_system_message// wasFUN_004480ef@ 0x004480ef. - Compatibility notes: the client's router passes
DAT_0052d498, which is the DPID slot used by both create and destroy system messages in this export.
DPSYS_DESTROYPLAYERORGROUP (0x00000005)#
SDK payload: DPMSG_DESTROYPLAYERORGROUP.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_DESTROYPLAYERORGROUP. |
dpId |
0x04 | 4 | uint32le | Destroyed player or group id. |
dwPlayerType |
0x08 | 4 | uint32le | DirectPlay player/group type. |
lpLocalData |
0x0c | 4 | pointer | Local player data pointer. |
dwLocalDataSize |
0x10 | 4 | uint32le | Local data size. |
lpRemoteData |
0x14 | 4 | pointer | Remote player data pointer. |
dwRemoteDataSize |
0x18 | 4 | uint32le | Remote data size. |
dpnName |
0x1c | 16 | DPNAME | DirectPlay name structure. |
- Direction: DirectPlay system -> client.
- Trigger: another player or group leaves or is destroyed.
- Handler (parse):
lotr2_net_handle_system_message// wasFUN_004480ef@ 0x004480ef. - Compatibility notes: before the game reaches state
DAT_0055c02c >= 3, the client rebroadcasts custom opcode 3 after removing the player slot.
DPSYS_ADDPLAYERTOGROUP (0x00000007)#
SDK payload: DPMSG_ADDPLAYERTOGROUP.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_ADDPLAYERTOGROUP. |
dpIdGroup |
0x04 | 4 | uint32le | Target group id. |
dpIdPlayer |
0x08 | 4 | uint32le | Added player id. |
- Direction: DirectPlay system -> client.
- Trigger: a DirectPlay group membership changes.
- Handler (parse):
lotr2_net_handle_system_message. - Compatibility notes: the observed client only logs this message.
DPSYS_DELETEPLAYERFROMGROUP (0x00000021)#
SDK payload: DPMSG_DELETEPLAYERFROMGROUP.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_DELETEPLAYERFROMGROUP. |
dpIdGroup |
0x04 | 4 | uint32le | Target group id. |
dpIdPlayer |
0x08 | 4 | uint32le | Removed player id. |
- Direction: DirectPlay system -> client.
- Trigger: a player leaves a DirectPlay group.
- Handler (parse):
lotr2_net_handle_system_message. - Compatibility notes: the observed client only logs this message.
DPSYS_SESSIONLOST (0x00000031)#
SDK payload: DPMSG_GENERIC.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_SESSIONLOST. |
- Direction: DirectPlay system -> client.
- Trigger: the DirectPlay session is lost.
- Handler (parse):
lotr2_net_handle_system_message. - Compatibility notes: the handler logs; teardown is handled elsewhere in session control paths.
DPSYS_HOST (0x00000101)#
SDK payload: DPMSG_HOST.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_HOST. |
dpIdNewHost |
0x04 | 4 | uint32le | New DirectPlay host id. |
- Direction: DirectPlay system -> client.
- Trigger: DirectPlay host migration.
- Handler (parse):
lotr2_net_handle_system_message. - Compatibility notes: the client does not compare
dpIdNewHost; receiving the system message is enough to setlotr2_net_is_host = 1.
DPSYS_SETPLAYERORGROUPDATA (0x00000102)#
SDK payload: DPMSG_SETPLAYERORGROUPDATA.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_SETPLAYERORGROUPDATA. |
dpId |
0x04 | 4 | uint32le | Player or group id. |
dwPlayerType |
0x08 | 4 | uint32le | DirectPlay player/group type. |
lpData |
0x0c | 4 | pointer | New data pointer. |
dwDataSize |
0x10 | 4 | uint32le | New data size. |
- Direction: DirectPlay system -> client.
- Trigger: player or group data changes through DirectPlay.
- Handler (parse):
lotr2_net_handle_system_message. - Compatibility notes: the observed client only logs this message.
DPSYS_SETPLAYERORGROUPNAME (0x00000103)#
SDK payload: DPMSG_SETPLAYERORGROUPNAME.
| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
dwType |
0x00 | 4 | uint32le | DPSYS_SETPLAYERORGROUPNAME. |
dpId |
0x04 | 4 | uint32le | Player or group id. |
dwPlayerType |
0x08 | 4 | uint32le | DirectPlay player/group type. |
dpnName |
0x0c | 16 | DPNAME | New DirectPlay name structure. |
- Direction: DirectPlay system -> client.
- Trigger: player or group name changes through DirectPlay.
- Handler (parse):
lotr2_net_handle_system_message. - Compatibility notes: the observed client only logs this message.
Receive HRESULTs#
The receive loop treats DP_OK as success, returns quietly on the no-message
HRESULT, and logs several DirectPlay error codes before returning. These are
transport status values, not message types.
Open Questions#
- Confirm exact DirectPlay SDK struct packing against a Win95 DirectX SDK.
- Capture system traffic on a stock-host join and disconnect.
Captures Needed#
- LAN trace covering create-player, host migration if possible, player destroy, and session lost.