This commit is contained in:
SepComet
2026-03-27 13:27:14 +08:00
parent ff9ee1291f
commit e5851795c7
43 changed files with 1544 additions and 35 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-03-27
@@ -0,0 +1,60 @@
## Context
The project already shares transport, envelope parsing, and message dispatch between Unity client and non-Unity server hosts. Stage 4 established that transport callbacks do not execute gameplay handlers inline, but session lifecycle behavior is still fragmented: transport establishment, login success, heartbeat timeout, disconnect, and reconnect intent are not modeled as separate states, and heartbeat logic is still entangled with business flow. Stage 5 needs a single host-agnostic lifecycle layer before later QoS and sync work build on unstable assumptions.
## Goals / Non-Goals
**Goals:**
- Introduce an explicit shared connection state model that distinguishes transport connection, authentication/login progress, steady-state session health, timeout, and reconnect intent.
- Centralize heartbeat timing, timeout detection, and reconnect scheduling into a shared session manager instead of distributing them across handlers and host code.
- Keep heartbeat infrastructure-focused: liveness detection, RTT measurement, and time sync only.
- Allow Unity client and non-Unity server hosts to observe the same lifecycle events while keeping host-specific reactions outside the shared core.
**Non-Goals:**
- Reworking message QoS or transport reliability semantics.
- Changing the envelope protocol or replacing KCP.
- Designing gameplay-specific reconnect UX, character resync, or rollback rules.
- Adding final production telemetry; detailed metrics belong to a later stage.
## Decisions
### Use an explicit shared connection state enum and session manager
A dedicated `SessionManager` backed by a `ConnectionState` model keeps lifecycle transitions in one place and makes transport-connected, login-pending, logged-in, timed-out, reconnecting, and login-failed states observable. This is better than inferring state from scattered booleans in handlers because later features such as reconnect backoff and QoS splitting need a stable state machine boundary.
Alternative considered: keep lifecycle flags in `NetworkManager` and server host adapters. Rejected because it would fork client/server behavior again right after the shared-network-foundation refactor.
### Treat heartbeat as infrastructure signals, not business state ownership
Heartbeat messages feed the session manager with liveness timestamps, RTT samples, and time-sync data, but they do not themselves declare login success or trigger reconnect policy. This keeps message handlers narrow and prevents hidden coupling where missing a heartbeat implicitly mutates business session state in unrelated code.
Alternative considered: let heartbeat handlers directly disconnect or reconnect. Rejected because it recreates the current layering problem and makes timeout policy hard to test.
### Make shared runtime own lifecycle orchestration, hosts own reactions
`SharedNetworkRuntime` should compose transport, message routing, and session lifecycle so both client and server use the same lifecycle rules. Unity `NetworkManager` and `ServerNetworkHost` consume lifecycle events and decide what to do next, such as UI updates, reconnect attempts, or server-side cleanup.
Alternative considered: introduce separate client/server session managers. Rejected because stage five explicitly aims to share the network底层 contract and keep host differences at the adapter layer.
### Represent reconnect as a scheduler policy, not an immediate side effect
Reconnect should be modeled as a transition into a reconnect-pending or reconnecting state with policy-owned timing, instead of directly restarting transport from inside a timeout callback. That makes backoff, disable/enable behavior, and tests deterministic.
Alternative considered: reconnect immediately inside timeout detection. Rejected because it couples timer evaluation to transport startup side effects and makes repeated failures difficult to reason about.
## Risks / Trade-offs
- [Risk] Introducing a state machine can expose ambiguities in existing login/heartbeat handlers. -> Mitigation: define explicit transition sources and add tests for login success, login failure, heartbeat timeout, disconnect, and reconnect scheduling.
- [Risk] Shared lifecycle ownership can blur the boundary between transport events and business authentication events. -> Mitigation: keep transport state inputs and login result inputs as separate session-manager APIs.
- [Risk] Reconnect policy may require host-specific decisions later. -> Mitigation: keep policy configuration injectable and host reactions event-driven rather than hardcoding Unity-only behavior.
- [Risk] Existing code may already assume that "connected" means "logged in". -> Mitigation: update host-facing APIs and TODO/documentation so callers consume explicit lifecycle states instead of legacy booleans.
## Migration Plan
1. Add shared lifecycle types (`ConnectionState`, session event model, heartbeat policy/session manager) without removing existing login/heartbeat flows yet.
2. Route transport-connect, login-result, heartbeat-received, and timeout inputs through the new session manager.
3. Update Unity client and server host adapters to observe lifecycle state changes from the shared runtime.
4. Remove or simplify duplicated timeout/reconnect logic from message handlers and host code.
5. Add edit mode tests that lock state transitions before beginning Stage 6 QoS work.
## Open Questions
- Whether the server host needs the exact same reconnect scheduling primitives as the client, or only the same state vocabulary.
- Whether login failure should transition to `Disconnected` immediately after reporting failure, or remain in a stable `LoginFailed` state until the host decides the next action.
- How much time-sync state should live in the session manager versus a separate clock-sync helper once Stage 6 begins.
@@ -0,0 +1,24 @@
## Why
Current networking distinguishes transport delivery from Unity threading, but it still does not distinguish transport connectivity, login success, heartbeat timeout, and reconnect flow as first-class session states. Stage 5 is needed now so client and server can share one coherent lifecycle model before QoS and sync optimization build on top of ambiguous state handling.
## What Changes
- Add a shared session lifecycle module that models disconnected, transport-connected, login-pending, logged-in, timeout, reconnecting, and login-failed states explicitly.
- Add a heartbeat policy that is limited to liveness checks, RTT measurement, and time synchronization, without owning login or reconnect decisions directly.
- Move timeout detection, disconnect transitions, and reconnect scheduling into a shared session manager instead of leaving them in message handlers or host-specific business code.
- Expose lifecycle state changes and session events so Unity client host and non-Unity server host can react without forking the underlying network core.
## Capabilities
### New Capabilities
- `network-session-lifecycle`: Shared connection, login, heartbeat, timeout, and reconnect state management for client and server hosts.
### Modified Capabilities
- `shared-network-foundation`: The shared runtime now includes host-agnostic session lifecycle management in addition to transport and message routing.
## Impact
- Affected code: `SharedNetworkRuntime`, `MessageManager`, `NetworkManager`, `ServerNetworkHost`, login/heartbeat handlers, and new session manager/state types.
- Affected behavior: login success no longer implies transport connect, heartbeat becomes a narrow infrastructure concern, and reconnect logic moves out of ad hoc business paths.
- Affected tests: edit mode tests need coverage for lifecycle transitions, timeout handling, login failure, and reconnect scheduling across shared client/server runtime paths.
@@ -0,0 +1,40 @@
## ADDED Requirements
### Requirement: Session lifecycle distinguishes transport and login state
The shared networking core SHALL expose an explicit session lifecycle model that distinguishes transport connectivity from login/authentication success. Hosts MUST be able to observe at least disconnected, transport-connected, login-pending, logged-in, login-failed, timed-out, and reconnecting lifecycle states without inferring them from unrelated message handlers.
#### Scenario: Transport connect does not imply login success
- **WHEN** the transport establishes a usable remote session but no login success message has been accepted yet
- **THEN** the shared lifecycle reports a transport-connected or login-pending state
- **THEN** it does not report the session as logged in
#### Scenario: Login success advances lifecycle independently
- **WHEN** the client or server session manager receives a successful login/authentication result for an active transport session
- **THEN** the shared lifecycle transitions that session into the logged-in state
- **THEN** hosts can react to that state change without conflating it with transport establishment
### Requirement: Heartbeat is limited to liveness, RTT, and time sync
The shared session lifecycle SHALL treat heartbeat traffic as infrastructure input for liveness detection, round-trip-time measurement, and clock synchronization only. Heartbeat processing MUST NOT itself own login success, login failure, or reconnect policy decisions.
#### Scenario: Heartbeat updates liveness and RTT only
- **WHEN** a heartbeat response is received for an active session
- **THEN** the session manager updates last-seen or timeout bookkeeping and RTT or clock-sync data
- **THEN** it does not mark the session logged in solely because the heartbeat succeeded
#### Scenario: Missing heartbeat triggers timeout state
- **WHEN** the configured heartbeat timeout elapses without a required heartbeat or other liveness signal
- **THEN** the session lifecycle transitions the session into a timed-out state
- **THEN** reconnect handling is delegated to the lifecycle reconnect policy rather than hidden inside the heartbeat handler itself
### Requirement: Timeout and reconnect are session-manager responsibilities
The shared networking core SHALL manage timeout detection, disconnect transitions, and reconnect scheduling through a session-manager component rather than implementing those decisions inside business message handlers.
#### Scenario: Timeout produces an observable reconnect transition
- **WHEN** a reconnect-capable host has a session that times out
- **THEN** the session manager emits a timeout-related lifecycle transition
- **THEN** it can subsequently move the session into a reconnecting or reconnect-pending state according to configured policy
#### Scenario: Login failure is distinct from transport disconnect
- **WHEN** authentication or login fails while the transport session is still active
- **THEN** the shared lifecycle reports a login-failed state
- **THEN** hosts can handle that failure separately from a transport disconnect or heartbeat timeout
@@ -0,0 +1,14 @@
## ADDED Requirements
### Requirement: Shared runtime owns host-agnostic session lifecycle orchestration
The shared network foundation SHALL include host-agnostic session lifecycle orchestration alongside transport startup and message routing. Client and server hosts MUST be able to compose the same shared runtime with a session manager that consumes transport events, login results, and heartbeat signals without depending on Unity-specific runtime types.
#### Scenario: Client host composes runtime with lifecycle manager
- **WHEN** the Unity client constructs its shared networking runtime
- **THEN** that runtime includes shared session lifecycle management in addition to transport and message routing
- **THEN** Unity-specific code remains responsible only for reacting to lifecycle state changes and driving host behavior
#### Scenario: Server host observes the same lifecycle vocabulary
- **WHEN** a non-Unity server host composes the shared networking runtime
- **THEN** it uses the same lifecycle state model and session-manager abstractions as the client-side shared runtime
- **THEN** server-specific cleanup or admission behavior stays in the server host adapter rather than forking the shared core contract
@@ -0,0 +1,19 @@
## 1. Shared Lifecycle Model
- [x] 1.1 Add shared lifecycle types for connection state, session events, and heartbeat/reconnect policy configuration.
- [x] 1.2 Implement a host-agnostic session manager that consumes transport-connected, login-result, heartbeat, timeout, and disconnect inputs.
## 2. Runtime Integration
- [x] 2.1 Extend `SharedNetworkRuntime` to compose the session manager alongside transport and message routing.
- [x] 2.2 Update `NetworkManager` and `ServerNetworkHost` to observe explicit lifecycle state changes instead of inferring session health from ad hoc flags.
## 3. Heartbeat And Login Flow Cleanup
- [x] 3.1 Refactor login and heartbeat handlers so heartbeat only updates liveness, RTT, and time-sync state.
- [x] 3.2 Remove timeout and reconnect decisions from business handlers and route them through session-manager policy APIs.
## 4. Verification And Documentation
- [x] 4.1 Add edit mode tests for transport-connected vs logged-in distinction, login failure, heartbeat timeout, and reconnect scheduling.
- [x] 4.2 Update `CodeX-TODO.md` and related network docs to reflect the new lifecycle layering and stage-five completion criteria.