From 92894d29048136cbcd98d5d8070a06d217e7497c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Sun, 31 May 2026 15:00:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E5=86=99=20network.rs=20?= =?UTF-8?q?=E2=80=94=20NetMessage/NetworkCmd/NetworkEvent=20+=20bincode=20?= =?UTF-8?q?serde=20=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- core/src/network.rs | 154 +++++++++++++++++++++++++++++++++----------- 1 file changed, 115 insertions(+), 39 deletions(-) diff --git a/core/src/network.rs b/core/src/network.rs index efb0b74..93c88b2 100644 --- a/core/src/network.rs +++ b/core/src/network.rs @@ -1,61 +1,137 @@ use serde::{Deserialize, Serialize}; -/// 游戏网络消息 +/// 网络传输的游戏消息(bincode 序列化) #[derive(Debug, Clone, Serialize, Deserialize)] -pub enum GameMessage { +pub enum NetMessage { Move { x: usize, y: usize, turn: u32 }, Undo { steps: u32 }, Resign, - Chat(String), - Heartbeat, } -/// 网络连接角色 +impl NetMessage { + pub fn to_bytes(&self) -> Vec { + bincode::serialize(self).unwrap_or_default() + } + + pub fn from_bytes(data: &[u8]) -> Option { + bincode::deserialize(data).ok() + } +} + +/// commands 层 → 网络线程 +#[derive(Debug)] +pub enum NetworkCmd { + SendMove { x: usize, y: usize, turn: u32 }, + SendUndo { steps: u32 }, + SendResign, + Shutdown, +} + +/// 网络线程 → commands 层 +#[derive(Debug, Clone)] +pub enum NetworkEvent { + RemoteMove { x: usize, y: usize }, + RemoteUndo { steps: u32 }, + RemoteResign, + ClientConnected, + ClientDisconnected, + Error(String), + Listening(u16), + Connected, +} + +/// 网络角色 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NetworkRole { Server, Client, } -/// 网络会话配置 -#[derive(Debug, Clone)] -pub struct NetworkConfig { - pub role: NetworkRole, - pub bind_port: u16, - pub remote_addr: String, - pub remote_port: u16, +/// 网络循环句柄(在独立线程中运行) +pub struct NetworkLoop { + role: NetworkRole, + running: bool, + cmd_rx: std::sync::mpsc::Receiver, + event_tx: std::sync::mpsc::Sender, } -/// 网络会话状态 -#[derive(Debug, Clone)] -pub struct NetworkSession { - pub role: NetworkRole, - pub is_connected: bool, - pub config: NetworkConfig, - pending_messages: Vec, -} - -impl NetworkSession { - pub fn new(config: NetworkConfig) -> Self { +impl NetworkLoop { + /// 创建 Server 端 + pub fn new_server( + cmd_rx: std::sync::mpsc::Receiver, + event_tx: std::sync::mpsc::Sender, + ) -> Self { Self { - role: config.role, - is_connected: false, - config, - pending_messages: Vec::new(), + role: NetworkRole::Server, + running: false, + cmd_rx, + event_tx, } } - /// 发送消息 (实际 renet 集成在 gui 层处理) - pub fn enqueue_message(&mut self, msg: GameMessage) { - self.pending_messages.push(msg); - } - - /// 取出待发送的消息 - pub fn drain_messages(&mut self) -> Vec { - std::mem::take(&mut self.pending_messages) - } - - pub fn set_connected(&mut self, connected: bool) { - self.is_connected = connected; + /// 创建 Client 端 + pub fn new_client( + cmd_rx: std::sync::mpsc::Receiver, + event_tx: std::sync::mpsc::Sender, + ) -> Self { + Self { + role: NetworkRole::Client, + running: false, + cmd_rx, + event_tx, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_net_message_move_roundtrip() { + let msg = NetMessage::Move { x: 7, y: 7, turn: 0 }; + let bytes = msg.to_bytes(); + let decoded = NetMessage::from_bytes(&bytes).unwrap(); + match decoded { + NetMessage::Move { x, y, turn } => { + assert_eq!(x, 7); + assert_eq!(y, 7); + assert_eq!(turn, 0); + } + _ => panic!("wrong variant"), + } + } + + #[test] + fn test_net_message_undo_roundtrip() { + let msg = NetMessage::Undo { steps: 1 }; + let bytes = msg.to_bytes(); + let decoded = NetMessage::from_bytes(&bytes).unwrap(); + assert!(matches!(decoded, NetMessage::Undo { steps: 1 })); + } + + #[test] + fn test_net_message_resign_roundtrip() { + let msg = NetMessage::Resign; + let bytes = msg.to_bytes(); + let decoded = NetMessage::from_bytes(&bytes).unwrap(); + assert!(matches!(decoded, NetMessage::Resign)); + } + + #[test] + fn test_network_cmd_channel() { + let (tx, rx) = std::sync::mpsc::channel(); + tx.send(NetworkCmd::SendMove { x: 7, y: 7, turn: 0 }).unwrap(); + tx.send(NetworkCmd::Shutdown).unwrap(); + + let mut received = Vec::new(); + while let Ok(cmd) = rx.try_recv() { + match cmd { + NetworkCmd::Shutdown => break, + NetworkCmd::SendMove { x, y, turn } => received.push((x, y, turn)), + _ => {} + } + } + assert_eq!(received, vec![(7, 7, 0)]); } }