feat: add broadcasting current turn and board view

This commit is contained in:
2026-08-17 19:39:46 +02:00
parent a096c990a9
commit a8a6e11350
7 changed files with 88 additions and 19 deletions

View File

@@ -3,9 +3,13 @@ use std::{
io::{self, Write},
};
use checkers::network::client::Client;
use checkers::network::{
client::{Client, ClientData},
network_identity::NetworkIdentity,
};
use log::{debug, error, info, warn};
use tokio::sync::mpsc;
use uuid::Uuid;
const QUIT_COMMAND: &str = "/quit";
const HELP_COMMAND: &str = "/help";
@@ -58,6 +62,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (stdin_sender, mut stdin_receiver) = mpsc::channel(1024);
let mut indentity: Option<NetworkIdentity> = None;
let mut is_my_turn: bool = false;
tokio::task::spawn_blocking(move || {
let stdin = std::io::stdin();
@@ -87,7 +94,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
tokio::select! {
msg = client_receiver.recv() => {
match msg {
Some(checkers::network::client::ClientData::GameStart {
Some(ClientData::GameStart {
identity,
board_view,
}) => {
@@ -95,20 +102,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
"Got new identity: {} and board_view. Game is about to start!",
identity
);
println!("{}", board_view.to_string(identity.id));
println!("{}", board_view.to_string(&identity.id));
indentity = Some(identity);
}
Some(checkers::network::client::ClientData::AvailableCaptures(capture_paths)) => {
Some(ClientData::BoardView(view)) => {
info!("New board state:\n{}", view.to_string(&indentity.as_ref().unwrap().id));
}
Some(ClientData::CurrentTurn(current_turn)) => {
is_my_turn = current_turn == indentity.as_ref().expect("Server sent us new current turn without telling us who we are!").id;
if is_my_turn {
info!("It's our turn!");
} else {
info!("It's the turn of our enemy!");
}
}
Some(ClientData::AvailableCaptures(capture_paths)) => {
todo!()
}
Some(checkers::network::client::ClientData::AvailableMoves(move_paths)) => todo!(),
Some(ClientData::AvailableMoves(move_paths)) => todo!(),
Some(checkers::network::client::ClientData::TextMessage(content)) => {
Some(ClientData::TextMessage(content)) => {
info!("Got message from the server: {}", content);
}
Some(checkers::network::client::ClientData::GameEnd(game_result)) => {
Some(ClientData::GameEnd(game_result)) => {
info!("Game has ended with the result: {:?}", game_result);
}

View File

@@ -32,21 +32,21 @@ impl Index<usize> for BoardView {
}
impl BoardView {
pub fn to_string(&self, owner: Uuid) -> String {
pub fn to_string(&self, owner: &Uuid) -> String {
(0..self.size)
.map(move |row| {
(0..self.size)
.map(move |column| match &self[row][column].pawn {
Some(pawn) => match pawn.state {
super::pawn::PawnState::Man => {
if pawn.owner == owner {
if pawn.owner == *owner {
'm'
} else {
'M'
}
}
super::pawn::PawnState::Dame => {
if pawn.owner == owner {
if pawn.owner == *owner {
'd'
} else {
'D'

View File

@@ -74,6 +74,10 @@ impl GameMaster {
BoardView::from(self.board.clone())
}
pub fn get_current_turn(&self) -> Uuid {
self.players.get_current_turn().id
}
pub fn get_current_player_captures(&self) -> Vec<CapturePath> {
self.board
.get_player_pawns_positions(self.players.get_current_turn())

View File

@@ -2,6 +2,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use log::{debug, error, info, warn};
use tokio::sync::mpsc::{self, Receiver, Sender};
use uuid::Uuid;
use crate::{
logic::{
@@ -42,10 +43,15 @@ pub enum ClientData {
identity: NetworkIdentity,
board_view: BoardView,
},
GameEnd(GameResult),
AvailableCaptures(Vec<CapturePath>),
AvailableMoves(Vec<MovePath>),
BoardView(BoardView),
CurrentTurn(Uuid),
TextMessage(String),
GameEnd(GameResult),
}
pub struct Client {
@@ -169,8 +175,12 @@ impl Client {
ServerMessage::AvailableCaptures { captures } => todo!(),
ServerMessage::AvailableMoves { moves } => todo!(),
ServerMessage::BroadcastBoardState { board } => todo!(),
ServerMessage::BroadcastCurrentTurn { active_player } => todo!(),
ServerMessage::BroadcastBoardState { board } => {
let _ = update_sender.send(ClientData::BoardView(board)).await;
},
ServerMessage::BroadcastCurrentTurn { active_player } => {
let _ = update_sender.send(ClientData::CurrentTurn(active_player)).await;
},
ServerMessage::GameEnd { result } => todo!(),
}
} else {

View File

@@ -51,8 +51,6 @@ pub enum ServerMessage {
board_view: BoardView,
},
BoardState(BoardView),
AvailableCaptures {
captures: Vec<CapturePath>,
},
@@ -61,8 +59,9 @@ pub enum ServerMessage {
},
BroadcastBoardState {
board: Board,
board: BoardView,
},
BroadcastCurrentTurn {
active_player: Uuid,
},

View File

@@ -1,5 +1,5 @@
pub mod client;
pub mod connection;
pub mod message;
mod network_identity;
pub mod network_identity;
pub mod server;

View File

@@ -257,6 +257,7 @@ impl Server {
}
self.game_master = Some(game_master);
self.on_player_action().await;
}
/* ======= Processing messages :D helper functions ======== */
@@ -290,20 +291,22 @@ impl Server {
identity.identity.name = fixed_name
}
fn process_capture(&mut self, capture_path: CapturePath) {
async fn process_capture(&mut self, capture_path: CapturePath) {
if let Some(gm) = self.game_master.as_mut() {
if gm.capture(&capture_path) {
debug!("Capture valid!");
self.on_player_action().await;
} else {
debug!("Invalid capture!");
}
}
}
fn process_move(&mut self, from: Position, to: Position) {
async fn process_move(&mut self, from: Position, to: Position) {
if let Some(gm) = self.game_master.as_mut() {
if gm.move_pawn(from, to) {
debug!("Move was valid!");
self.on_player_action().await;
} else {
debug!("Move was invalid!");
}
@@ -330,6 +333,37 @@ impl Server {
}
}
/* === Sending messages === */
/// Wrapper around broadcast_current_turn and broadcast_board_view. Should be used after every
/// players move
async fn on_player_action(&mut self) {
self.broadcast_board_view().await;
self.broadcast_current_turn().await;
}
async fn broadcast_board_view(&mut self) {
if let Some(gm) = &self.game_master {
let msg = Message::new(ServerMessage::BroadcastBoardState {
board: gm.get_board_view(),
});
self.broadcast_message(msg).await;
} else {
error!("Cannot broadcast board view as game manager is not set!");
}
}
async fn broadcast_current_turn(&mut self) {
if let Some(gm) = &self.game_master {
let msg = Message::new(ServerMessage::BroadcastCurrentTurn {
active_player: gm.get_current_turn(),
});
self.broadcast_message(msg).await;
} else {
error!("Cannot broadcast current turn as game master doesn't exists!!!!!!!!!");
}
}
/* === Helper methods === */
async fn send_message(