Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
LasmGratel committed Sep 29, 2021
1 parent 8a69d7f commit 15d3e97
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 231 deletions.
6 changes: 4 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cardgame-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ serde = {version = "1.0", features = ["derive"]}
bincode = "1.3.3"
message-io = "0.13"
uuid = {version = "0.8", features = ["serde", "v4"]}
async-std = "1.9.0"
async-std = "1.10"
humantime = "2.1.0"
timeago = "0.3.0"
4 changes: 3 additions & 1 deletion cardgame-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ cardgame = {path = "../cardgame"}
message-io = "0.13"
uuid = {version = "0.8", features = ["serde", "v4"]}
humantime = "2.1.0"
timeago = "0.3.0"
timeago = "0.3.0"
anyhow = "1.0"
async-std = "1.10"
234 changes: 68 additions & 166 deletions cardgame-server/src/main.rs

Large diffs are not rendered by default.

234 changes: 174 additions & 60 deletions cardgame-server/src/server_lobby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use std::collections::HashMap;
use message_io::network::{NetworkController, Endpoint, SendStatus};

use cardgame::user::{UserId, UserState};
use cardgame::{Game, Lobby, LobbyError, Room, RoomState, S2CMessage};
use cardgame::{Game, Lobby, LobbyError, Room, RoomState, S2CMessage, RoomError, GameState};
use bimap::{BiMap, BiHashMap};
use anyhow::Error;
use crate::server_network::{NetworkManager, MessagePacket, MessageTarget};

/// 大厅的服务器实现。
pub struct ServerLobby<'a> {
Expand Down Expand Up @@ -38,7 +40,35 @@ impl ServerLobby<'_> {
}
}

pub fn join_room(&mut self, room_name: &str, user: String) -> Result<&Room, LobbyError> {
pub fn connect(&mut self, user_id: UserId, endpoint: Endpoint) {
self.login(user_id.clone());
self.network.connect(user_id.clone(), endpoint);

match self.user_states.get(&user_id) {
None => {
self.user_states.insert(user_id, UserState::Idle);
}
Some(state) => {
match state {
UserState::Idle => {
}
UserState::Matchmaking => {
// 断线后取消匹配
self.user_states.insert(user_id, UserState::Idle);
}
UserState::Playing(_room) => {
// TODO 断线重连
}
}
}
}
}

pub fn join_room_by_endpoint(&mut self, room_name: &str, endpoint: Endpoint) -> Result<MessagePacket, LobbyError> {
self.join_room(room_name, self.get_user(&endpoint).expect("User not found").to_string())
}

pub fn join_room(&mut self, room_name: &str, user: UserId) -> Result<MessagePacket, LobbyError> {
if !self.rooms.contains_key(room_name) {
self.rooms
.insert(room_name.to_string(), Room::new(room_name.to_string()));
Expand All @@ -54,99 +84,183 @@ impl ServerLobby<'_> {

if room.users.len() == 3 {
room.state = RoomState::Ready;

match room.start_game() {
Ok((landlord_player, players)) => {
for player in players {
self.network.send_to_user(&player.user, &S2CMessage::GameStarted(player.cards.clone(), landlord_player.user.clone()));
self.user_states.insert(player.user.clone(), UserState::Playing(room_name.to_string()));
}
}
Err(err) => {
return Err(LobbyError::RoomErr(err));
}
}
}
Ok(room)
Ok((MessageTarget::Reply, S2CMessage::RoomJoined(room_name.to_string())))
}
}

pub fn get_room(&self, user_id: &str) -> Option<&Room> {
pub fn start_game(&mut self, room: &mut Room) -> Result<(), Error> {
let room_name = room.name.clone();
match room.start_game() {
Ok((landlord_player, players)) => {
for player in players {
self.network.send_to_user(&player.user, &S2CMessage::GameStarted(player.cards.clone(), landlord_player.user.clone()));
self.user_states.insert(player.user.clone(), UserState::Playing(room_name.clone()));
}
}
Err(err) => {
self.send_to_room(&room.name, &S2CMessage::RoomErr(err.clone()));
return Err(Error::from(err));
}
}
Ok(())
}

pub fn start_game_by_name(&mut self, room_name: &str) -> Result<&mut Room, RoomError> {
let room = self.rooms.get_mut(room_name);
if room.is_none() {
return Err(RoomError::NotReady);
}
let room = room.unwrap();
match room.start_game() {
Ok((landlord_player, players)) => {
for player in players {
self.network.send_to_user(&player.user, &S2CMessage::GameStarted(player.cards.clone(), landlord_player.user.clone()));
self.user_states.insert(player.user.clone(), UserState::Playing(room_name.to_string()));
}
}
Err(err) => {
return Err(err);
}
}
Ok(room)
}

pub fn rematch_vote(&mut self, user: &str, vote: bool) -> Result<MessagePacket, RoomError> {
if let Some(room) = self.get_room_by_user_mut(user) {
let current_state = room.state.clone();
if let RoomState::WaitingForRematch(count) = current_state {
return if vote {
if count + 1 == 3 {
room.game.reset();

self.start_game(room);
}
room.state = RoomState::WaitingForRematch(count + 1);
Ok((MessageTarget::Reply, S2CMessage::RematchVote(user.to_string(), vote, count + 1)))
} else {
let name = room.name.clone();
*room = Room::new(name);
Ok((MessageTarget::Reply, S2CMessage::RematchVote(user.to_string(), vote, count)))
}
}
}
Err(RoomError::NotReady)
}

pub fn send_packet(&self, packet: MessagePacket) -> Option<SendStatus> {
match packet.0 {
MessageTarget::All => {
self.network.send_to_all(&packet.1).ok().map(|_| SendStatus::Sent)
}
MessageTarget::Reply => {
None
}
MessageTarget::Endpoint(endpoint) => {
self.network.send_to_endpoint(&packet.1, endpoint)
}
MessageTarget::User(user) => {
self.network.send_to_user(&user, &packet.1)
}
MessageTarget::Room(room) => {
self.send_to_room(&room, &packet.1)
}
}
}

pub fn choose_landlord_by_endpoint(&mut self, endpoint: &Endpoint, choose: bool) -> Result<MessagePacket, Error> {
let user = self.get_user(endpoint).expect("No user found by endpoint").clone();
let network = &self.network;
if let Some(room) = self.get_room_by_user_mut(&user) {
// 尚未开始叫地主阶段
if room.game.state != GameState::WaitingForLandlord {
return Err(Error::from(RoomError::NotStarted));
}
// 不是当前的地主玩家
if room.game.players[room.game.landlord_index].user != user {
return Err(Error::from(RoomError::NotLandlordPlayer));
}
if choose { // 叫地主
room.game.run().expect("Game cannot run");
// 通知所有玩家地主人选

Ok((MessageTarget::Room(room.name.clone()), S2CMessage::LordCards(room.game.current_player().user.clone(), room.game.landlord_cards.clone())))
} else { // 不叫
room.game.move_landlord_index();
// 通知下一个地主

Ok((MessageTarget::Room(room.name.clone()), S2CMessage::LandlordMove(room.game.landlord_player().user.clone())))
}
} else {
// 房间还未准备好
Err(Error::from(RoomError::NotReady))
}
}

pub fn get_user(&self, endpoint: &Endpoint) -> Option<&UserId> {
self.network.user_map.get_by_right(endpoint)
}

pub fn get_room_by_user(&self, user_id: &str) -> Option<&Room> {
if let Some(UserState::Playing(room_name)) = self.user_states.get(user_id) {
self.rooms.get(room_name)
} else {
None
}
}

pub fn get_room_mut(&mut self, user_id: &str) -> Option<&mut Room> {
pub fn get_room_by_user_mut(&mut self, user_id: &str) -> Option<&mut Room> {
if let Some(UserState::Playing(room_name)) = self.user_states.get(user_id) {
self.rooms.get_mut(room_name)
} else {
None
}
}

pub fn send_to_room(&self, room_name: &str, message: &S2CMessage) -> Option<()> {
let room = self.get_room(room_name)?;
pub fn get_room_by_endpoint(&self, endpoint: &Endpoint) -> Option<&Room> {
self.get_room_by_user(self.get_user(endpoint)?)
}

pub fn get_room_by_endpoint_mut(&mut self, endpoint: &Endpoint) -> Option<&mut Room> {
let user = self.get_user(endpoint)?.to_string();
self.get_room_by_user_mut(&user)
}

pub fn send_to_room(&self, room_name: &str, message: &S2CMessage) -> Option<SendStatus> {
let room = self.get_room_by_user(room_name)?;
for user in room.users.iter() {
let status = self.network.send_to_user(user, message)?;
if status != SendStatus::Sent {
return None
}
}
Some(())
Some(SendStatus::Sent)
}
}

impl Lobby for ServerLobby<'_> {
fn login(&mut self, user: String) {
if !self.user_states.contains_key(&user) {
self.user_states.insert(user.clone(), UserState::Idle);
}
self.users.push(user);
// if !self.user_states.contains_key(&user) {
// self.user_states.insert(user, UserState::Idle);
// }
}

fn disconnect(&mut self, user: &str) {
if let Some(pos) = self.users.iter().position(|x| x == user) {
self.users.remove(pos);
}
}
}

pub struct NetworkManager<'a> {
pub user_map: BiMap<UserId, Endpoint>,

controller: &'a NetworkController,
}

impl NetworkManager<'_> {
fn new(controller: &NetworkController) -> NetworkManager {
NetworkManager {
user_map: BiHashMap::new(),
controller
}
}

fn connect(&mut self, user_id: UserId, endpoint: Endpoint) {
self.user_map.insert(user_id, endpoint);
}

fn send_to_user(&self, user_id: &str, message: &S2CMessage) -> Option<SendStatus> {
let endpoint = self.user_map.get_by_left(user_id)?;
let to_send = bincode::serialize(message).ok()?;
Some(self.controller.send(*endpoint, &to_send))
}

/// Send a message to all clients registered
///
/// # Arguments
///
/// * `message`: message to send
///
/// returns: Result<usize, usize> amount of clients, error index
///
fn send_to_all(&self, message: &S2CMessage) -> Result<usize, usize> {
let mut i: usize = 0;
if let Ok(to_send) = bincode::serialize(message) {
for endpoint in self.user_map.right_values() {
if self.controller.send(*endpoint, &to_send) == SendStatus::Sent {
i += 1;
} else {
return Err(i);
}
}
Ok(i)
} else {
Err(0)
}
}
}
Loading

0 comments on commit 15d3e97

Please sign in to comment.