Skip to content

Network (DirectPlay 3)#

Purpose#

Multiplayer transport and session management built on DirectPlay 3 (DPLAYX.DLL). Handles service-provider selection, connection init, hosting and joining sessions, player creation, and a custom application-message stream (reliable + unreliable) layered over IDirectPlay3::Send / Receive.

Key entry points#

Symbol Address Role
lotr2_net_start_session 0x4d243e Session entry; sets active flag, runs join handshake wait
lotr2_net_setup_session 0x4d266d InitializeConnection, Open (host/join), CreatePlayer
lotr2_net_create_dplay3 0x4d2d1f DirectPlayCreate + QueryInterface IID_IDirectPlay3
lotr2_net_shutdown 0x4d23d0 Close + Release the IDirectPlay3 object
lotr2_net_leave_session 0x4d25c6 DestroyPlayer + shutdown
lotr2_net_set_player_data 0x4d260d SetPlayerData (vtable +0x7c)
lotr2_net_poll_messages 0x4d36f0 Receive loop; routes system vs app messages
lotr2_net_dp_send 0x4d39d5 IDirectPlay3::Send wrapper
lotr2_net_send_message 0x448641 Pack frame, checksum, reliable triple-send
lotr2_net_dispatch_app_message 0x448362 Validate + dedupe + dispatch app message
lotr2_net_handle_system_message 0x4480ef DPSYS_* handler (sets host on DPSYS_HOST)
lotr2_net_checksum 0x448c6c 8-bit additive payload checksum (skips 4-byte header)
lotr2_net_buffer_checksum 0x448cbd Full-buffer 8-bit additive sum from offset 0
lotr2_net_strided_checksum 0x448d0e Strided row/column checksum for sync tables
lotr2_net_partial_checksum 0x448d8e Checksum of buffer slice [skip .. size); used by sync refresh
lotr2_net_payload_write / lotr2_net_payload_read 0x448dee / 0x448e2a Payload cursors (lotr2_net_payload_write_ptr / _read_ptr)
lotr2_net_on_join_handshake 0x44a03b Completes join; sets lotr2_net_handshake_done
lotr2_net_reset_send_state 0x448832 Reset send slots / counters pre-play
lotr2_net_clear_send_slot_table 0x448b3f Zero 6×10 send-slot table
lotr2_net_clear_recv_dedupe_table 0x448b9a Zero 7×0x28 receive dedupe table
lotr2_net_clear_msg_history_table 0x448bfa Zero per-player message history
lotr2_net_refresh_player_sync_checksums 0x448e65 Recompute per-player sync checksum bytes pre-send
lotr2_net_host_check_sync_ready 0x44927a Host sync gate; may send opcode 0x0f
lotr2_net_compare_player_sync_slot 0x4493e9 Compare sync row across connected slots
lotr2_net_apply_host_sync_masks 0x449553 Apply host sync bitfield; client sends opcode 0x12
lotr2_net_host_resolve_sync_conflicts 0x44973f Host compares checksum rows; sends opcode 0x10
lotr2_net_host_replay_sync_deltas 0x449ab4 Host replays non-zero sync delta table; sends opcode 0x10
lotr2_net_sync_clear_battle_tiles 0x449c22 Clears battle tile occupancy before sync (opcode 0x12)
lotr2_net_sync_apply_state_slice 0x449c3d Apply state slice during sync; sends opcodes 0x50/0x14/0x13
lotr2_net_sync_restore_state_slice 0x449d7c Restore state slice during sync; sends opcode 0x0e
lotr2_net_reset_send_state_ok 0x4d2653 Wrapper: lotr2_net_reset_send_state() then return 1
lotr2_net_sync_local_faction_id 0x43b22b Assign local faction id at session start
Service-provider dialog 0x4d2a1e / 0x4d2ac0 DirectPlayEnumerate picker
Host/Join + browse dialogs 0x4d2a48 / 0x4d2a99 / 0x4d2a6f / 0x4d3120 Session setup UI + EnumSessions
lotr2_net_dlg_sp_list_hwnd 0x502a78 SP picker listbox handle
lotr2_net_dlg_sp_sel_index 0x502a84 Selected SP list index
lotr2_net_dlg_session_name_hwnd 0x502a70 Host session-name edit control
lotr2_net_dlg_browse_list_hwnd 0x502a7c Session browser listbox handle
DirectPlayCreate / DirectPlayEnumerate 0x4db1e4 / 0x4db1de DPLAYX.DLL ordinal-1 / ordinal-2 import stubs

App-message handlers (pass 50 complete)#

Pack/unpack functions are indexed by opcode via PTR_LAB_004f06b8 (pack) and PTR_LAB_004f0820 (unpack). All 90 opcode slots now have semantic lotr2_net_pack_* / lotr2_net_unpack_* names (pass 49 + pass 50). Deferred turn actions go through lotr2_net_deferred_action_enqueue (was opcode 0x53) and lotr2_net_deferred_queue_drain.

Opcode Pack Unpack
0x01 lotr2_net_pack_local_id lotr2_net_unpack_join_handshake_request
0x02 lotr2_net_pack_join_data lotr2_net_on_join_handshake
0x03 lotr2_net_pack_player_roster_sync lotr2_net_unpack_player_roster_sync
0x0a lotr2_net_pack_heartbeat_toggle lotr2_net_unpack_heartbeat_toggle
0x04 lotr2_net_pack_begin_campaign lotr2_net_unpack_begin_campaign
0x0b lotr2_net_pack_sync_ui_viewport lotr2_net_unpack_sync_ui_viewport
0x1f lotr2_net_pack_save_game lotr2_net_unpack_save_game
0x23 lotr2_net_pack_upkeep_increase lotr2_net_unpack_upkeep_decrease
0x36 lotr2_net_pack_move_army_to_cell lotr2_net_unpack_move_army_to_cell
0x56 lotr2_net_pack_write_save_slot lotr2_net_unpack_load_save_slot
0x57 lotr2_net_pack_menu_selection_inc lotr2_net_unpack_menu_selection_dec

Full opcode catalog: ../../protocols/dplay-app-messages.md. Apply renames via ../../tools/ghidra/net_renames_pass50.py.

Key globals#

Symbol Address Role
lotr2_net_dplay3 0x4ff400 IDirectPlay3* object
lotr2_net_local_player_id 0x4ff408 Local player DPID
lotr2_net_iid_dplay3 0x4eb0d8 IID_IDirectPlay3 GUID blob
lotr2_net_player_data 0x4ff404 Player-data buffer (SetPlayerData)
lotr2_net_session_active 0x55a370 Session-running gate (read by 100+ game sites)
lotr2_net_handshake_done 0x55a854 Join handshake-complete flag
lotr2_net_is_host 0x5636e0 Host vs client role
lotr2_net_session_preselected 0x4ff410 EnumSessions preselected-entry flag
lotr2_net_send_slot 0x52a578 Rolling send-slot index (wraps 1..0x27)
lotr2_net_recv_frame 0x52d490 Receive frame buffer (header + payload)
lotr2_net_recv_length 0x52d491 Received payload length byte
lotr2_net_recv_checksum 0x52d492 Received checksum byte
lotr2_net_recv_seq_flags 0x52d493 Received sequence / resend flags
lotr2_net_payload_write_ptr 0x52d488 Payload write cursor
lotr2_net_payload_read_ptr 0x52d460 Payload read cursor
lotr2_net_send_slots 0x52d5a0 Send slot array base (stride 0x104)

Dependencies#

  • DPLAYX.DLLDirectPlayCreate (ord 1), DirectPlayEnumerate (ord 2), IDirectPlay3 COM interface.
  • USER32.DLLDialogBoxParamA session/SP dialogs, SendMessageA list boxes.
  • KERNEL32.DLLGetTickCount / Sleep for send pacing and handshake timeout.
  • ui/MODULE.md — main window handle lotr2_ui_hwnd_main.

Data files#

  • None on disk. Session name default string "Lords2 Session1", player short name "Nobleman".

Cross-references#

Open questions#

  • Authoritative opcode table dump needs a binary that passes anchor validation against this Ghidra export; generated docs currently mark unknown entries as TBD.
  • Which service-provider GUID(s) are used (modem / serial / IPX / TCP).
  • Orphan handler bodies at 0x44ef1f0x44f598 have no xrefs; defer until jump-table dump at 0x004f0820 is validated (see symbol-map pass 28).
  • Opcodes 0x08 and 0x09 have no distinct handler pair in the 0x449e layout; table slots may alias other handlers (see pass-20 notes in symbol-map).