Skip to content

Fix CS2 14197 ReplyConnection sig and net message handle usage - #86

Closed
xiaoyueyoqwq wants to merge 1 commit into
Source2ZE:mainfrom
xiaoyueyoqwq:fix/14197-netmessage-handles
Closed

xiaoyueyoqwq wants to merge 1 commit into
Source2ZE:mainfrom
xiaoyueyoqwq:fix/14197-netmessage-handles

Conversation

@xiaoyueyoqwq

@xiaoyueyoqwq xiaoyueyoqwq commented Nov 12, 2026 •

Copy link
Copy Markdown

Summary

Fixes #84 — MultiAddonManager fails to load on CS2 1.41.9.7 / build 2000943 (Failed to lookup the signature for ReplyConnection), and would crash on the first client message even once it loaded.

  • Linux ReplyConnection signature extended. On 2000943 the compiler swapped the function's first two movs (55 41 B8 … B9 … 48 89 E5 41 57 41 56 48 8D 95); the shorter existing pattern now matches two functions so lookup fails.
  • Hook_SendNetMessage no longer touches the message handle. 14197 turned INetworkMessageInternal handles into plain NetMessageInfo_t records with no vtable, so GetNetMessageInfo() was a virtual call through a name string. CNetMessage's own vtable is unchanged, so pData->GetMessageId() is used directly.
  • GetAddonSignonStateMessage works around the SDK's stale declarations. INetworkMessages::FindNetworkMessagePartial moved from slot 14 to slot 10 and the returned record is allocated via its m_pfnAllocate field at +0x8. The helper reaches both through the raw vtable/record until the SDK headers catch up (s2sdk#124 pending upstream).

Analysis largely from @jakejarrett's notes in #84, verified against s2sdk#124.

Test plan

  • Linux build compiles (gcc, SteamRT sniper container, s2sdk@cs2 headers)
  • Plugin loads on live 14197 server: meta list shows MultiAddonManager (v1.7.3-7fc2d6f) loaded, [MultiAddonManager] Plugin loaded successfully!, Refreshing addons, Logged on to Steam
  • Hook_SendNetMessage path exercised continuously (SourceTV/HLTV client receiving messages), no crash
  • Addon push path verified end-to-end on live server: host_workshop_map 3789922008 → HostStateRequest ... addons(3789922008) → Mounting addon → SignonState messages sent → real client connected with S2C_CONNECTION [addons:'3789922008'] and validated — no crash
  • Windows build untested (no build env here)

Generated with Devin

- Extend the Linux ReplyConnection signature; on build 2000943 the
  compiler swapped its first two movs and the short pattern now matches
  two functions
- Net message handles are now plain NetMessageInfo_t records with no
  vtable, and INetworkMessages::FindNetworkMessagePartial moved from
  slot 14 to 10, so look it up through the raw vtable and allocate via
  the record's function pointer until the SDK headers catch up
- Hook_SendNetMessage reads the id with CNetMessage::GetMessageId(),
  whose vtable is unchanged

Co-authored-by: jakejarrett <5661105+jakejarrett@users.noreply.github.com>
@xiaoyueyoqwq
xiaoyueyoqwq force-pushed the fix/14197-netmessage-handles branch from f28edf6 to a603897 Compare November 12, 2026 07:30
@xiaoyueyoqwq

Copy link
Copy Markdown
Author

Live verification results on CS2 1.41.9.7 / build 2000943 (Linux dedicated, Metamod 2.0 git1483, SteamRT sniper runtime).

End-to-end addon flow — all green

Switched to workshop map 3789922008 with a real client connected:

profile via host_workshop_map 3789922008
HostStateRequest::Start(HSR_GAME): loop(levelload) id(3) addons(3789922008)
Mounting addon '3789922008'
SV:  addon='3789922008'
Sending S2C_CONNECTION to <client> [addons:'3789922008']
"AI<65280><[U:1:753702285]><>" STEAM USERID validated
  • ReplyConnection hook fires on connect and pushes the addon list correctly (new signature resolves)
  • GetAddonSignonStateMessage produces valid CNETMsg_SignonState [7] messages via the slot-10 vcall + m_pfnAllocate (signon went through, client validated)
  • Hook_SendNetMessage handles all outbound traffic incl. SourceTV/HLTV — ~15 min continuous operation, zero crashes

Signature uniqueness check on the actual binary

Scanned the server's libengine2.so (build 2000943):

55 41 B8 ? ? ? ? B9 ? ? ? ? 48 89 E5                     → 2 matches (0x4f9d80, 0x877d00)
55 41 B8 ? ? ? ? B9 ? ? ? ? 48 89 E5 41 57               → 1 match  (0x4f9d80)
55 41 B8 ? ? ? ? B9 ? ? ? ? 48 89 E5 41 57 41 56 48 8D 95 → 1 match  (0x4f9d80)

Worth noting: the published v1.7.3 release binary was built at 3e04eff, i.e. before 7fc2d6f — it still carries the pre-14197 55 B9 … 41 B8 signature, which matches 0 functions on this build. That's the lookup failure servers are hitting (#84). Current main's signature does resolve uniquely here; this PR extends it anyway since the shared prefix alone already collides at 0x877d00 — one prologue shuffle away from an ambiguous match.

The runtime side is the load-critical half: with only the signature fixed, the plugin loads but crashes on the first client message (GetNetMessageInfo() virtual call on the vtable-less handle — same fault class as roflmuffin/CounterStrikeSharp#1491).

@xen-000 xen-000 closed this Nov 12, 2026
@xiaoyueyoqwq

Copy link
Copy Markdown
Author

Understood on the close — for anyone landing here: rebuilding MAM against s2sdk 81020d1 (alliedmodders/s2sdk#124) together with the 7fc2d6f signature resolves the crash with no source changes, as confirmed in #84. That is the cleaner long-term path since the ABI details live in the SDK headers.

This branch still works as a stopgap — the build above was verified end-to-end on 2000943 (workshop map switch, addon push, real client join, zero crashes) — for anyone who needs a working binary before an official rebuild ships.

One small request for future contributions: a one-line rationale when closing a PR helps contributors understand the direction. Happy to help test the official build when it lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

from last update

2 participants