RUDPClient/openspec/specs/kcp-transport/spec.md

6.9 KiB

kcp-transport Specification

Purpose

TBD - created by archiving change introduce-kcp-transport. Update Purpose after archive.

Requirements

Requirement: Client mode uses a default KCP session

The transport SHALL support a client mode that is constructed with a default remote endpoint and creates exactly one default KCP session after StartAsync. Calls to Send(byte[] data) in client mode MUST encode the payload through that session and emit the resulting UDP datagrams to the configured remote endpoint.

Scenario: Client sends through the default remote session

  • WHEN the application starts a client-mode transport and calls Send with a business payload
  • THEN the transport routes the payload through the default KCP session
  • THEN the UDP socket sends the encoded datagrams to the configured remote endpoint

Requirement: Server mode isolates KCP session state per remote endpoint

The transport SHALL support a server mode that receives UDP datagrams from multiple remote endpoints and maintains independent KCP session state for each active remote endpoint. A datagram received from one endpoint MUST only be applied to that endpoint's session, and SendToAll(byte[] data) MUST encode and enqueue the payload once per active session.

Scenario: Two remotes do not share KCP state

  • WHEN a server-mode transport receives KCP traffic from two different remote endpoints
  • THEN the transport creates or reuses separate KCP session state for each endpoint
  • THEN payloads reconstructed for one endpoint are delivered with that endpoint as the sender

Scenario: Broadcast writes through each active session

  • WHEN the application calls SendToAll while the server transport has multiple active sessions
  • THEN the transport encodes the payload for each active KCP session
  • THEN the UDP socket sends datagrams to every active remote endpoint without collapsing them into a shared session

Requirement: OnReceive only dispatches complete KCP payloads

The transport SHALL invoke OnReceive only after a complete application payload has been reconstructed from Kcp.Recv. Raw UDP packets, partial KCP fragments, and transport-level acknowledgements MUST NOT be surfaced to the message layer.

Scenario: Fragmented payload is withheld until complete

  • WHEN a business message spans multiple UDP datagrams and only a subset of those datagrams has been processed
  • THEN the transport does not invoke OnReceive

Scenario: Reassembled payload is forwarded to the message layer

  • WHEN the remaining datagrams for a fragmented KCP message are processed and Kcp.Recv yields a complete payload
  • THEN the transport invokes OnReceive exactly once with the reconstructed payload and the originating remote endpoint

Requirement: Active sessions are driven until stop and cleaned up on shutdown

The transport SHALL continue driving KCP timers for every active session while it is running, so retransmissions, acknowledgements, and flushes can progress even when no new UDP datagrams arrive. Calling Stop() MUST stop the receive and update loops, release the UDP socket, and clear active session state.

Scenario: Idle sessions still receive KCP timer updates

  • WHEN the transport has an active session with pending KCP work but no new incoming UDP datagrams
  • THEN the transport continues calling the KCP update path according to its internal schedule

Scenario: Stop releases transport resources

  • WHEN the application calls Stop() on a running transport
  • THEN the transport stops receiving new UDP datagrams
  • THEN the transport clears its active KCP session state before shutdown completes

Requirement: KCP is the sole reliable transport implementation

The project SHALL expose KcpTransport as the only reliable ITransport implementation used by runtime networking paths. Reliable control-plane business messages, including login, logout, heartbeat, and other ordered session-management traffic, MUST continue to flow through KCP-backed sessions. ShootInput and CombatEvent MUST also continue to use the reliable ordered KCP lane, while high-frequency MoveInput and PlayerState synchronization MAY use a separate sync lane defined by the sync-strategy capability.

Scenario: Runtime networking uses KCP for reliable control and gameplay event delivery

  • WHEN the application constructs the reliable transport used for login, session control, shooting requests, and combat-result traffic
  • THEN that transport instance is KcpTransport
  • THEN reliable control and gameplay-event payloads are sent and received through KCP session state

Scenario: High-frequency sync is allowed to bypass reliable ordered delivery

  • WHEN the runtime routes MoveInput or PlayerState according to the high-frequency sync strategy
  • THEN those messages are not forced to use the reliable ordered KCP lane
  • THEN reliable KCP delivery remains available for control-plane traffic, ShootInput, and CombatEvent

Requirement: Legacy reliable UDP entry points are retired

The codebase SHALL NOT keep a directly instantiable ReliableUdpTransport entry point that implies a second reliable delivery mechanism. If a non-reliable UDP transport is needed in the future, it MUST use a distinct name and MUST NOT claim reliable semantics.

Scenario: Legacy reliable transport is not available to callers

  • WHEN developers inspect the transport implementations available to runtime code
  • THEN they do not find a usable ReliableUdpTransport class representing reliable delivery
  • THEN the remaining transport naming makes the reliable-versus-unreliable boundary explicit

Requirement: KCP transport can emit structured metrics through an optional module

KcpTransport SHALL allow callers to provide an optional transport metrics module without changing the shared ITransport contract. While running, KcpTransport MUST publish transport lifecycle, session creation and disposal, logical payload traffic, UDP datagram traffic, and transport-stage errors into that module, and it MUST expose a current metrics snapshot query for diagnostics and tests.

Scenario: Injected metrics module receives KCP traffic statistics

  • WHEN a caller starts a KcpTransport, sends and receives payloads, and then stops the transport
  • THEN the injected metrics module receives enough events to aggregate the run's payload, datagram, session, and error statistics
  • THEN diagnostics code can query the current snapshot without reading the exported report file

Scenario: Default metrics module exports on KCP transport shutdown

  • WHEN a caller uses KcpTransport without providing a custom metrics module and later calls Stop()
  • THEN the transport uses its built-in metrics module to finalize the run summary during shutdown
  • THEN the transport emits the final JSON report and compact console summary exactly once for that run