docs: add Phase 8-2 networking status, spec, plan, and deferred items
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,14 @@
|
|||||||
- **raycast_all (다중 hit)** — 가장 가까운 hit만 반환.
|
- **raycast_all (다중 hit)** — 가장 가까운 hit만 반환.
|
||||||
- **BVH 조기 종료 최적화** — 모든 리프 검사 후 최소 t 선택. front-to-back 순회 미구현.
|
- **BVH 조기 종료 최적화** — 모든 리프 검사 후 최소 t 선택. front-to-back 순회 미구현.
|
||||||
|
|
||||||
|
## Phase 8-2
|
||||||
|
|
||||||
|
- **상태 동기화 (스냅샷)** — 미구현. 서버→클라이언트 월드 상태 전송.
|
||||||
|
- **보간 / 예측** — 미구현. 클라이언트 측 스무딩.
|
||||||
|
- **지연 보상** — 미구현. 서버 측 히트 판정 보정.
|
||||||
|
- **신뢰성 계층** — 미구현. 패킷 재전송, 순서 보장.
|
||||||
|
- **암호화 / 인증** — 미구현.
|
||||||
|
|
||||||
## Phase 8-1
|
## Phase 8-1
|
||||||
|
|
||||||
- **자동 내비메시 생성** — Recast 스타일 복셀화 미구현. 수동 정의만.
|
- **자동 내비메시 생성** — Recast 스타일 복셀화 미구현. 수동 정의만.
|
||||||
|
|||||||
@@ -125,6 +125,13 @@
|
|||||||
- voltex_ai: A* pathfinding on triangle graph (center-point path)
|
- voltex_ai: A* pathfinding on triangle graph (center-point path)
|
||||||
- voltex_ai: Steering behaviors (seek, flee, arrive, wander, follow_path)
|
- voltex_ai: Steering behaviors (seek, flee, arrive, wander, follow_path)
|
||||||
|
|
||||||
|
### Phase 8-2: Networking Foundation
|
||||||
|
- voltex_net: Packet protocol (Connect, Accept, Disconnect, Ping, Pong, UserData)
|
||||||
|
- voltex_net: Binary serialization/deserialization
|
||||||
|
- voltex_net: Non-blocking UDP socket wrapper
|
||||||
|
- voltex_net: NetServer (client management, broadcast)
|
||||||
|
- voltex_net: NetClient (server connection, handshake)
|
||||||
|
|
||||||
## Crate 구조
|
## Crate 구조
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -136,10 +143,11 @@ crates/
|
|||||||
├── voltex_asset — Handle<T>, AssetStorage<T>, Assets
|
├── voltex_asset — Handle<T>, AssetStorage<T>, Assets
|
||||||
├── voltex_physics — Collider, ContactPoint, BvhTree, RigidBody, detect_collisions, physics_step, raycast
|
├── voltex_physics — Collider, ContactPoint, BvhTree, RigidBody, detect_collisions, physics_step, raycast
|
||||||
├── voltex_audio — AudioClip, WAV parser, mixing, WASAPI backend, AudioSystem, MixGroup, spatial
|
├── voltex_audio — AudioClip, WAV parser, mixing, WASAPI backend, AudioSystem, MixGroup, spatial
|
||||||
└── voltex_ai — NavMesh, A* pathfinding, steering behaviors
|
├── voltex_ai — NavMesh, A* pathfinding, steering behaviors
|
||||||
|
└── voltex_net — UDP packets, NetServer, NetClient
|
||||||
```
|
```
|
||||||
|
|
||||||
## 테스트: 228개 전부 통과
|
## 테스트: 236개 전부 통과
|
||||||
|
|
||||||
- voltex_asset: 14
|
- voltex_asset: 14
|
||||||
- voltex_audio: 35 (audio_clip 2 + wav 5 + mixing 11 + audio_system 2 + spatial 8 + mix_group 7)
|
- voltex_audio: 35 (audio_clip 2 + wav 5 + mixing 11 + audio_system 2 + spatial 8 + mix_group 7)
|
||||||
@@ -148,6 +156,7 @@ crates/
|
|||||||
- voltex_physics: 52 (collider 2 + narrow 11 + bvh 5 + collision 7 + rigid_body 3 + integrator 3 + solver 5 + ray 10 + raycast 6)
|
- voltex_physics: 52 (collider 2 + narrow 11 + bvh 5 + collision 7 + rigid_body 3 + integrator 3 + solver 5 + ray 10 + raycast 6)
|
||||||
- voltex_platform: 3
|
- voltex_platform: 3
|
||||||
- voltex_ai: 15 (navmesh 4 + pathfinding 5 + steering 6)
|
- voltex_ai: 15 (navmesh 4 + pathfinding 5 + steering 6)
|
||||||
|
- voltex_net: 8 (packet 7 + integration 1)
|
||||||
- voltex_renderer: 33 (20 + SSGI 3 + RT 3 + bloom 3 + tonemap 4)
|
- voltex_renderer: 33 (20 + SSGI 3 + RT 3 + bloom 3 + tonemap 4)
|
||||||
|
|
||||||
## Examples (11개)
|
## Examples (11개)
|
||||||
@@ -164,7 +173,7 @@ crates/
|
|||||||
- audio_demo — 사인파 오디오 재생
|
- audio_demo — 사인파 오디오 재생
|
||||||
- deferred_demo — 디퍼드 렌더링 + 다중 포인트 라이트
|
- deferred_demo — 디퍼드 렌더링 + 다중 포인트 라이트
|
||||||
|
|
||||||
## 다음: Phase 8-2 (네트워킹) / 8-3 (스크립팅) / 8-4 (에디터) — Stretch Goal
|
## 다음: Phase 8-3 (스크립팅) / 8-4 (에디터) — Stretch Goal
|
||||||
|
|
||||||
스펙 참조: `docs/superpowers/specs/2026-03-24-voltex-engine-design.md`
|
스펙 참조: `docs/superpowers/specs/2026-03-24-voltex-engine-design.md`
|
||||||
|
|
||||||
|
|||||||
43
docs/superpowers/plans/2026-03-25-phase8-2-networking.md
Normal file
43
docs/superpowers/plans/2026-03-25-phase8-2-networking.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Phase 8-2: Networking Foundation Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** UDP 기반 클라이언트-서버 네트워킹 인프라 — 패킷 직렬화, 연결 핸드셰이크, 데이터 송수신
|
||||||
|
|
||||||
|
**Architecture:** `voltex_net` crate 신규. 바이너리 패킷 프로토콜 + non-blocking UdpSocket 래퍼 + NetServer(클라이언트 관리) + NetClient(서버 연결). std::net만 사용.
|
||||||
|
|
||||||
|
**Tech Stack:** Rust, std::net::UdpSocket
|
||||||
|
|
||||||
|
**Spec:** `docs/superpowers/specs/2026-03-25-phase8-2-networking.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: Crate + Packet 직렬화
|
||||||
|
|
||||||
|
Create crate, packet.rs with Packet enum and binary serialization.
|
||||||
|
|
||||||
|
- Cargo.toml: no dependencies
|
||||||
|
- Workspace: add members + workspace.dependencies
|
||||||
|
- Packet enum: Connect, Accept, Disconnect, Ping, Pong, UserData
|
||||||
|
- Header: [type u8, payload_len u16 LE, reserved u8]
|
||||||
|
- to_bytes(), from_bytes()
|
||||||
|
- 6 tests: roundtrip per variant + invalid bytes error
|
||||||
|
|
||||||
|
Commit: `feat(net): add voltex_net crate with packet serialization`
|
||||||
|
|
||||||
|
## Task 2: NetSocket + NetServer + NetClient
|
||||||
|
|
||||||
|
Create socket.rs, server.rs, client.rs with full networking.
|
||||||
|
|
||||||
|
- NetSocket: bind(non-blocking), send_to, recv_from
|
||||||
|
- ClientInfo, ServerEvent, NetServer: poll, broadcast, send_to_client
|
||||||
|
- ClientEvent, NetClient: connect, poll, send, is_connected, disconnect
|
||||||
|
- Tests: localhost handshake, UserData roundtrip, disconnect
|
||||||
|
|
||||||
|
Commit: `feat(net): add UDP server/client with connection management`
|
||||||
|
|
||||||
|
## Task 3: Documentation
|
||||||
|
|
||||||
|
Update STATUS.md and DEFERRED.md.
|
||||||
|
|
||||||
|
Commit: `docs: add Phase 8-2 networking status and deferred items`
|
||||||
174
docs/superpowers/specs/2026-03-25-phase8-2-networking.md
Normal file
174
docs/superpowers/specs/2026-03-25-phase8-2-networking.md
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# Phase 8-2: Networking Foundation — Design Spec
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`voltex_net` crate를 신규 생성한다. UDP 소켓 래핑, 패킷 직렬화, 클라이언트-서버 연결 관리를 구현한다.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- 패킷 프로토콜 (Connect, Accept, Disconnect, Ping, Pong, UserData)
|
||||||
|
- 바이너리 직렬화/역직렬화
|
||||||
|
- Non-blocking UDP 소켓 래퍼
|
||||||
|
- NetServer (클라이언트 관리, broadcast)
|
||||||
|
- NetClient (서버 연결, 핸드셰이크)
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
|
||||||
|
- 상태 동기화 (스냅샷)
|
||||||
|
- 보간 / 예측
|
||||||
|
- 지연 보상
|
||||||
|
- 신뢰성 계층 (재전송, 순서 보장)
|
||||||
|
- 암호화 / 인증
|
||||||
|
|
||||||
|
## Module Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
crates/voltex_net/
|
||||||
|
├── Cargo.toml
|
||||||
|
└── src/
|
||||||
|
├── lib.rs
|
||||||
|
├── packet.rs — Packet enum, to_bytes, from_bytes
|
||||||
|
├── socket.rs — NetSocket (UdpSocket wrapper)
|
||||||
|
├── server.rs — NetServer
|
||||||
|
└── client.rs — NetClient
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- 없음 (std::net::UdpSocket만 사용)
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
### Packet
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Packet {
|
||||||
|
Connect { client_name: String },
|
||||||
|
Accept { client_id: u32 },
|
||||||
|
Disconnect { client_id: u32 },
|
||||||
|
Ping { timestamp: u64 },
|
||||||
|
Pong { timestamp: u64 },
|
||||||
|
UserData { client_id: u32, data: Vec<u8> },
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 직렬화 포맷
|
||||||
|
|
||||||
|
```
|
||||||
|
[type: u8] [payload_len: u16 LE] [reserved: u8] [payload...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Type IDs: Connect=1, Accept=2, Disconnect=3, Ping=4, Pong=5, UserData=6
|
||||||
|
|
||||||
|
Payload encoding:
|
||||||
|
- Connect: name_len(u16) + name_bytes
|
||||||
|
- Accept: client_id(u32)
|
||||||
|
- Disconnect: client_id(u32)
|
||||||
|
- Ping/Pong: timestamp(u64)
|
||||||
|
- UserData: client_id(u32) + data_len(u16) + data_bytes
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl Packet {
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8>
|
||||||
|
pub fn from_bytes(data: &[u8]) -> Result<Packet, String>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### NetSocket
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct NetSocket {
|
||||||
|
socket: UdpSocket,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `bind(addr: &str) -> Result<Self, String>` — bind + set_nonblocking(true)
|
||||||
|
- `send_to(&self, packet: &Packet, addr: SocketAddr) -> Result<(), String>`
|
||||||
|
- `recv_from(&self) -> Option<(Packet, SocketAddr)>` — None if WouldBlock
|
||||||
|
|
||||||
|
### ClientInfo
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct ClientInfo {
|
||||||
|
pub id: u32,
|
||||||
|
pub addr: SocketAddr,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### NetServer
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct NetServer {
|
||||||
|
socket: NetSocket,
|
||||||
|
clients: HashMap<u32, ClientInfo>,
|
||||||
|
next_id: u32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `new(addr: &str) -> Result<Self, String>`
|
||||||
|
- `poll(&mut self) -> Vec<ServerEvent>` — process incoming packets
|
||||||
|
- `broadcast(&self, packet: &Packet)` — send to all clients
|
||||||
|
- `send_to_client(&self, client_id: u32, packet: &Packet)`
|
||||||
|
- `clients(&self) -> &HashMap<u32, ClientInfo>`
|
||||||
|
- `client_count(&self) -> usize`
|
||||||
|
|
||||||
|
### ServerEvent
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub enum ServerEvent {
|
||||||
|
ClientConnected { client_id: u32, name: String },
|
||||||
|
ClientDisconnected { client_id: u32 },
|
||||||
|
PacketReceived { client_id: u32, packet: Packet },
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### NetClient
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct NetClient {
|
||||||
|
socket: NetSocket,
|
||||||
|
server_addr: SocketAddr,
|
||||||
|
client_id: Option<u32>,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `new(local_addr: &str, server_addr: &str, name: &str) -> Result<Self, String>`
|
||||||
|
- `connect(&self)` — send Connect packet
|
||||||
|
- `poll(&mut self) -> Vec<ClientEvent>` — process incoming
|
||||||
|
- `send(&self, packet: &Packet) -> Result<(), String>`
|
||||||
|
- `is_connected(&self) -> bool`
|
||||||
|
- `client_id(&self) -> Option<u32>`
|
||||||
|
- `disconnect(&self)`
|
||||||
|
|
||||||
|
### ClientEvent
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub enum ClientEvent {
|
||||||
|
Connected { client_id: u32 },
|
||||||
|
Disconnected,
|
||||||
|
PacketReceived { packet: Packet },
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
|
||||||
|
### packet.rs
|
||||||
|
- Connect 라운드트립
|
||||||
|
- Accept 라운드트립
|
||||||
|
- Disconnect 라운드트립
|
||||||
|
- Ping/Pong 라운드트립
|
||||||
|
- UserData 라운드트립
|
||||||
|
- 잘못된 바이트 → 에러
|
||||||
|
|
||||||
|
### socket.rs
|
||||||
|
- localhost 바인드
|
||||||
|
- send + recv 라운드트립
|
||||||
|
|
||||||
|
### server.rs + client.rs (통합)
|
||||||
|
- 서버 시작 + 클라이언트 연결 → Accept 수신
|
||||||
|
- 다수 클라이언트 연결
|
||||||
|
- 클라이언트 Disconnect → 서버에서 제거
|
||||||
|
- UserData 송수신
|
||||||
Reference in New Issue
Block a user