You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
4.9 KiB

use crate::app::BoardView;
use crate::types::SelectedTile;
use board_network::protocol::{ClientMessage, ServerMessage};
use board_shared::game::Game;
use futures::stream::{SplitSink, SplitStream};
use futures::{SinkExt, StreamExt};
use gloo_dialogs::alert;
use gloo_net::websocket::futures::WebSocket;
use gloo_net::websocket::Message;
use std::cell::RefCell;
use std::rc::Rc;
use yew::platform::spawn_local;
use yew::prelude::*;
#[derive(Properties)]
pub struct RemoteGameViewProps {
pub write: Rc<RefCell<SplitSink<WebSocket, Message>>>,
pub read: Rc<RefCell<SplitStream<WebSocket>>>,
pub player_name: String,
pub room_name: Option<String>,
}
impl PartialEq for RemoteGameViewProps {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.write, &other.write)
&& Rc::ptr_eq(&self.read, &other.read)
&& self.player_name == other.player_name
&& self.room_name == other.room_name
}
}
#[function_component(RemoteGameView)]
pub fn remote_game_view(
RemoteGameViewProps {
write,
read,
player_name,
room_name,
}: &RemoteGameViewProps,
) -> Html {
macro_rules! send_client_message {
($write:expr, $message:expr) => {{
let write = $write.clone();
spawn_local(async move {
write
.borrow_mut()
.send(Message::Text(
serde_json::to_string(&$message).expect("Cannot serialize"),
))
.await
.unwrap();
});
}};
}
let selected_tile = use_state(|| SelectedTile::None);
let is_started = use_state(|| false);
let current_player_turn = use_state(|| 0);
let game = use_state(Game::default);
{
let player_name = player_name.clone();
let room_name = room_name.clone();
let write = write.clone();
use_effect_with_deps(
move |_| {
send_client_message!(
write,
if let Some(room_name) = room_name {
ClientMessage::JoinRoom(room_name, player_name)
} else {
ClientMessage::CreateRoom(player_name)
}
);
},
(),
);
let is_started = is_started.clone();
let current_player_turn = current_player_turn.clone();
let read = read.clone();
use_effect_with_deps(
move |_| {
spawn_local(async move {
while let Some(event) = read.borrow_mut().next().await {
if let Message::Text(msg) = event.unwrap() {
match serde_json::from_str::<ServerMessage>(&msg) {
Ok(ServerMessage::JoinedRoom {
room_name,
has_started,
..
}) => {
alert(&format!("Joined room {}", room_name));
is_started.set(has_started);
}
Ok(ServerMessage::PlayerTurn(player_id)) => {
current_player_turn.set(player_id);
is_started.set(true);
}
r => {
alert(&format!("{:?}", r));
}
};
}
}
});
|| {}
},
(),
);
}
let on_validate_click = {
let write = write.clone();
Callback::from(move |_| {
send_client_message!(write, ClientMessage::Validate);
})
};
let on_start_game_click = {
let write = write.clone();
Callback::from(move |_| {
send_client_message!(write, ClientMessage::StartGame);
})
};
let on_equals_select = {
Callback::from(move |_| {
selected_tile.set(SelectedTile::Equals);
})
};
html! {
<main>
<h1>{"Remote Game"}</h1>
<BoardView board={game.board.clone()} on_click={Callback::from(|_| {})} />
<div class="row">
<button onclick={on_equals_select} class="button">{"="}</button>
if *is_started {
<button onclick={on_validate_click} class="button">{"Validate"}</button>
} else {
<button onclick={on_start_game_click} class="button">{"Start"}</button>
}
</div>
if *is_started {
<div class="row">
<p>{format!("Player {}'s turn", *current_player_turn)}</p>
</div>
}
</main>
}
}