完成阶段 4

This commit is contained in:
SepComet
2026-03-27 08:04:25 +08:00
parent f053c9ad0d
commit ff9ee1291f
47 changed files with 2481 additions and 460 deletions
+15 -1
View File
@@ -1,4 +1,4 @@
# kcp-transport Specification
# kcp-transport Specification
## Purpose
TBD - created by archiving change introduce-kcp-transport. Update Purpose after archive.
@@ -46,4 +46,18 @@ The transport SHALL continue driving KCP timers for every active session while i
- **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 business messages, including login, heartbeat, player input, and player state synchronization, MUST continue to flow through KCP-backed sessions rather than any legacy reliable UDP compatibility class.
#### Scenario: Runtime networking uses KCP for reliable delivery
- **WHEN** the application constructs the transport used by `MessageManager` for its normal runtime networking path
- **THEN** that transport instance is `KcpTransport`
- **THEN** reliable business payloads are sent and received through KCP session state
### 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
@@ -0,0 +1,43 @@
# network-main-thread-dispatch Specification
## Purpose
Define the main-thread dispatch boundary between background transport callbacks and Unity runtime message handling.
## Requirements
### Requirement: Transport callbacks enqueue network message dispatch work
The network application layer SHALL place a thread-safe queue between `ITransport.OnReceive` callbacks and message handler execution. When a transport callback produces a valid application envelope, the callback path MUST enqueue dispatch work and return without invoking registered business handlers inline.
#### Scenario: Valid payload is deferred instead of dispatched inline
- **WHEN** a transport implementation raises `OnReceive` with a valid encoded application message
- **THEN** the message layer enqueues one dispatch work item for that message
- **THEN** the registered handler is not executed during the transport callback itself
#### Scenario: Invalid payload does not block later queued messages
- **WHEN** the transport callback receives malformed bytes followed by a valid application message
- **THEN** the malformed payload is handled as an error without enqueuing executable work
- **THEN** the later valid message can still be enqueued and processed normally
### Requirement: Main-thread drain executes queued handlers in receive order
The runtime SHALL provide an explicit main-thread drain step that executes queued network dispatch work in FIFO order. Message handlers, gameplay state mutation, and UI-facing reactions triggered by received messages MUST run only through this main-thread drain path.
#### Scenario: Drain executes queued work on demand
- **WHEN** one or more network messages have been enqueued from transport callbacks
- **THEN** no registered handler runs until the main-thread dispatcher performs a drain step
- **THEN** each queued handler executes during that drain step on the Unity main thread path
#### Scenario: Messages preserve receive order through the dispatcher
- **WHEN** multiple valid messages are enqueued in sequence for the same runtime
- **THEN** the main-thread dispatcher invokes their handlers in the same order they were enqueued
### Requirement: Runtime network host pumps the dispatcher each frame
The Unity-side runtime network host SHALL integrate a client-specific main-thread dispatcher implementation into its frame loop so queued network work is drained regularly while the network stack is running. That Unity dispatcher implementation MUST satisfy the shared host-dispatch abstraction used by the shared message-routing layer, while the transport background thread responsibilities remain limited to socket receive, KCP input/update, and transport-level error handling.
#### Scenario: Network host drains queued messages during runtime
- **WHEN** the Unity client runtime has started networking and a message is queued from the transport layer
- **THEN** the Unity client host performs dispatcher draining during its Unity update loop
- **THEN** the queued handler runs without the transport layer directly touching Unity objects
#### Scenario: Transport layer remains free of Unity object mutation
- **WHEN** developers inspect the responsibilities of the transport receive path after the shared networking refactor
- **THEN** they find socket receive, KCP processing, and enqueue/error handling only
- **THEN** Unity object mutation and UI updates are performed through the Unity host's main-thread dispatcher implementation rather than the transport callback path
@@ -0,0 +1,39 @@
# shared-network-foundation Specification
## Purpose
Define the shared transport and message-routing foundation that both client and server hosts use without depending on Unity-specific runtime host classes.
## Requirements
### Requirement: Shared network core is host-agnostic
The project SHALL provide a shared network core that contains transport, session, envelope parsing, and message-routing behavior without depending on Unity-specific runtime host classes such as `MonoBehaviour` or frame-loop callbacks. Both client and server networking hosts MUST be able to use this shared core.
#### Scenario: Client host uses shared network core
- **WHEN** the Unity client constructs its runtime networking stack
- **THEN** it uses the shared transport and message-routing core for transport startup, sending, receiving, and handler registration
- **THEN** Unity-specific logic remains in the client host adapter rather than in the shared core classes
#### Scenario: Server host can use the same core without Unity types
- **WHEN** a server-side host constructs the runtime networking stack
- **THEN** it can use the same shared transport and message-routing core without depending on Unity host classes
- **THEN** server-specific startup and lifetime control are provided by a separate host adapter
### Requirement: Message routing uses a host-provided dispatcher strategy
The shared message-routing layer SHALL execute received business handlers through a host-provided dispatcher abstraction rather than constructing a Unity-specific dispatcher internally. The host MUST be able to choose the dispatch strategy that matches its runtime model.
#### Scenario: Unity client injects a queued main-thread dispatcher
- **WHEN** the Unity client constructs the shared message-routing layer
- **THEN** it supplies a dispatcher implementation that queues work for later execution on the Unity main thread
- **THEN** received handlers run according to that injected client dispatch strategy
#### Scenario: Server host injects a non-Unity dispatch strategy
- **WHEN** a non-Unity server host constructs the shared message-routing layer
- **THEN** it supplies a dispatcher implementation that does not rely on Unity frame-loop semantics
- **THEN** the shared message-routing layer still processes received messages correctly through that host-selected strategy
### Requirement: Shared core preserves current transport and message contracts
The shared client/server foundation SHALL preserve the existing `ITransport` send/receive contract and the envelope-based `MessageManager` routing model so client and server hosts exchange the same business payload format through the same transport abstractions.
#### Scenario: Shared hosts exchange the same envelope format
- **WHEN** a client host sends a business message through the shared core to a server host using the shared core
- **THEN** the message is encoded using the same envelope contract on the client side
- **THEN** the server host decodes and routes it through the shared message-routing layer without a host-specific protocol fork