4.9 KiB
Network
Channels
| Channel | Transport | Endpoint | Content |
|---|---|---|---|
| Login + Matching2 | TCP 31313 (unencrypted) | shadNet | protobuf commands (shadnet.proto): auth, worlds, rooms, room events |
| STUN | UDP 31314 | shadNet | 21-byte ping {cmd=0x01, online_id[16], local_ip} every 5 s; server reflects mapped address |
| Summon broker | HTTP TCP 31315 | shadNet | `/summon_messenger/create |
| FromSoftware online API | HTTPS → HTTP | thehuntersdream.com | messages/bloodstains/etc. (ss4.scej-network.jp override) |
| Gameplay | UDP, one physical socket per process | peer | Bloodborne netcode through PS4 P2P sockets |
| Account service (BBSC) | HTTP TCP 31316 | host (server/account_service) |
/api/register, /api/verify, /api/resend, /api/status — email-verified sign-up; creates shadNet accounts with RegistrationSecretKey |
Server in this project: <server-ip> (Tailscale), seamless enabled. See server/shadnet.cfg.
shadp2p P2P transport (src/core/libraries/network/p2p_sockets.cpp) — CONFIRMED
- One UDP socket per emulator process (
SHADPS4_P2P_PORTor runtime-assigned). - Every datagram: 4-byte header
[source vport u16 BE][dest vport u16 BE]+ payload (≤ UDP max − 4). - vport
0xFFFFis reserved for signaling; game sockets bind a vport (0 = ephemeral from 30000). - No reliability, ordering, sequence numbers, acks or timestamps at this layer. Anything of that kind is Bloodborne's own protocol inside the payload. UNKNOWN.
- Transport lifetime is the process; it is not tied to a room. STRONGLY INDICATED.
Matching2 signaling (np_matching2_signaling.cpp) — CONFIRMED
Packet (0x32 bytes, packed):
| Offset | Field | Notes |
|---|---|---|
| 0x00 | magic SHAD |
|
| 0x04 | type 0x21 |
|
| 0x05 | kind | 1 Offer, 2 Accept, 3 Check, 4 CheckAck |
| 0x06 | room_id u64 | |
| 0x0E | from_member_id u16 | |
| 0x10 | to_member_id u16 | |
| 0x12 | online_id_from[16] | |
| 0x22 | mapped_addr u32, mapped_port u16, reserved u16 | UDP source endpoint preferred over self-report |
| 0x2A | nonce u64 | RTT from Check → CheckAck |
- Retry 350 ms; pending handshake dead after 10 s →
SIGNALING_EVENT_DEAD. - Established peers have no emulator-side keepalive timeout. STRONGLY INDICATED.
DEADis also raised when a roomMEMBER_LEFTarrives (np_matching2_mm.cpp).- Star topology honored via
signaling_main_member.
Summon HTTP (game-owned JSON, relayed by shadNet) — CONFIRMED
| Route | Sender | Purpose |
|---|---|---|
create |
guest (repeated) | Advertise; response may carry a claim (SummonDataCreateResponse with claim members) or a host placement header |
get |
host (repeated) | Search; returns SummonDataList |
request |
host | Claim {CharaId, TargetUserId, TargetCharaId, SessionId, UserId} (serializer 0x01E98650) |
delete |
either | Remove advertisement (retained in seamless active states unless Force/SeamlessLeave) |
SummonData: base64 of 224 bytes (v3). Transform floats at 0x5C–0x68; online name at 0x44; available-result count at 0x79 (shadNet normalizes 0 → 1 in search responses).
Placement header v1: ASCII 1,<packed map hex>,… (map, 4 IEEE-754 bit patterns, signed SOS area), ≤ 128 bytes, no CR/LF.
Broker states: Advertised → Preparing (cross-map) → Claimed → Delivered → Consumed; TTL 130 s, 15 min for seamless active states.
Room lifecycle on shadNet (cmd_matching.cpp) — CONFIRMED
LeaveRoom: remove member; empty room destroyed; owner leaving → succession list or first member;MEMBER_LEFT (0x1102)to others.- TCP disconnect → same path (
CleanupMatchingOnDisconnect). - Rooms are in memory; server restart drops all.
Bloodborne netcode (inside the P2P payload)
| Question | Finding | Status |
|---|---|---|
| Message types / serialization | Not decoded by anyone | UNKNOWN |
| Behavior sync module | SprjChrBehaviorSyncModule |
STRONGLY INDICATED exists |
| Event sync | SyncEvent, SetNoNetSync; EMEVD Set Network Sync State |
STRONGLY INDICATED |
| Game-level timeouts | OnRoomTimeOut, OnP2PTimeOut, OnSummonTimeOut |
CONFIRMED names; timeouts UNKNOWN |
| Wander demon messages | SendFrpgNet_DeadWanderDemon, SendFrpgNet_EscapeWanderDemon |
CONFIRMED names |
Protocol decision for the project
No new gameplay protocol is justified yet: all in-session sync already works natively. The only missing information today is coordination (who follows whom, destination, session intent). If a control channel is needed it should ride the existing placement-header mechanism (bump to v2) or a small shadNet route. Revisit after Phase 1 tests.
Rates (targets for any control traffic we add)
| Class | Rate |
|---|---|
| Continuous state | none (native netcode already does this) |
| Coordination events (travel, death, boss clear) | on event, ≤ 1/s |
| Heartbeat | reuse STUN ping 5 s |
| Resync snapshot | on reconnect only |