Impl sending/receiving emotes
This commit is contained in:
parent
36dd43bb70
commit
105cd880f2
5 changed files with 192 additions and 25 deletions
|
@ -11,7 +11,9 @@ use crate::constants::{
|
||||||
BACKEND_CLEANUP_INTERVAL_SECONDS, COLS, GAME_CLEANUP_TIMEOUT, PLAYER_CLEANUP_TIMEOUT,
|
BACKEND_CLEANUP_INTERVAL_SECONDS, COLS, GAME_CLEANUP_TIMEOUT, PLAYER_CLEANUP_TIMEOUT,
|
||||||
PLAYER_COUNT_LIMIT, ROWS, TURN_SECONDS,
|
PLAYER_COUNT_LIMIT, ROWS, TURN_SECONDS,
|
||||||
};
|
};
|
||||||
use crate::state::{board_from_string, new_string_board, string_from_board, BoardState, Turn, EmoteEnum};
|
use crate::state::{
|
||||||
|
board_from_string, new_string_board, string_from_board, BoardState, EmoteEnum, Turn,
|
||||||
|
};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::mpsc::{Receiver, RecvTimeoutError, SyncSender};
|
use std::sync::mpsc::{Receiver, RecvTimeoutError, SyncSender};
|
||||||
|
@ -1159,7 +1161,7 @@ impl DBHandler {
|
||||||
_conn_result.as_ref().unwrap()
|
_conn_result.as_ref().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut prepared_stmt = conn.prepare("SELECT games.cyan_player, games.magenta_player FROM games JOIN players WHERE players.id = ?, games.id = players.game_id;")
|
let mut prepared_stmt = conn.prepare("SELECT games.cyan_player, games.magenta_player FROM games JOIN players WHERE players.id = ? AND games.id = players.game_id;")
|
||||||
.map_err(|_| String::from("Failed to prepare db query for getting opponent id for sending emote"))?;
|
.map_err(|_| String::from("Failed to prepare db query for getting opponent id for sending emote"))?;
|
||||||
let row_result: Result<(Option<u32>, Option<u32>), RusqliteError> =
|
let row_result: Result<(Option<u32>, Option<u32>), RusqliteError> =
|
||||||
prepared_stmt.query_row([sender_id], |row| Ok((row.get(0).ok(), row.get(1).ok())));
|
prepared_stmt.query_row([sender_id], |row| Ok((row.get(0).ok(), row.get(1).ok())));
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
//You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
//You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::BACKEND_PHRASE_MAX_LENGTH,
|
constants::BACKEND_PHRASE_MAX_LENGTH,
|
||||||
db_handler::{CheckPairingType, DBHandlerRequest, GetIDSenderType}, state::EmoteEnum,
|
db_handler::{CheckPairingType, DBHandlerRequest, GetIDSenderType},
|
||||||
|
state::EmoteEnum,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -48,6 +48,33 @@
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
}
|
||||||
|
div.emote_wrapper {
|
||||||
|
grid-row: 3;
|
||||||
|
grid-column: 8;
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
button.emote {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
b.emote {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
button#emote_smile {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
button#emote_neutral {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
button#emote_frown {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 3;
|
||||||
|
}
|
||||||
|
button#emote_think {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 4;
|
||||||
|
}
|
||||||
button.networkedMultiplayer {
|
button.networkedMultiplayer {
|
||||||
grid-row: 1;
|
grid-row: 1;
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
|
|
|
@ -98,20 +98,6 @@ impl GameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_network_current_side(&self) -> Option<Turn> {
|
|
||||||
if let GameState::NetworkedMultiplayer {
|
|
||||||
paired: _,
|
|
||||||
current_side,
|
|
||||||
current_turn: _,
|
|
||||||
phrase: _,
|
|
||||||
} = *self
|
|
||||||
{
|
|
||||||
current_side
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_networked_current_turn(&mut self, turn: Turn) {
|
pub fn set_networked_current_turn(&mut self, turn: Turn) {
|
||||||
if let GameState::NetworkedMultiplayer {
|
if let GameState::NetworkedMultiplayer {
|
||||||
paired: _,
|
paired: _,
|
||||||
|
@ -573,6 +559,12 @@ pub struct PlaceTokenResponse {
|
||||||
pub board: String,
|
pub board: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct SendEmoteRequestResponse {
|
||||||
|
pub r#type: String,
|
||||||
|
pub status: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum NetworkedGameState {
|
pub enum NetworkedGameState {
|
||||||
CyanTurn,
|
CyanTurn,
|
||||||
|
@ -638,6 +630,17 @@ impl From<EmoteEnum> for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EmoteEnum {
|
||||||
|
pub fn get_unicode(&self) -> char {
|
||||||
|
match *self {
|
||||||
|
EmoteEnum::Smile => '🙂',
|
||||||
|
EmoteEnum::Neutral => '😐',
|
||||||
|
EmoteEnum::Frown => '🙁',
|
||||||
|
EmoteEnum::Think => '🤔',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -18,9 +18,9 @@ use crate::html_helper::{
|
||||||
};
|
};
|
||||||
use crate::random_helper::get_seeded_random;
|
use crate::random_helper::get_seeded_random;
|
||||||
use crate::state::{
|
use crate::state::{
|
||||||
board_from_string, BoardState, GameState, GameStateResponse, MainMenuMessage,
|
board_from_string, BoardState, EmoteEnum, GameState, GameStateResponse, MainMenuMessage,
|
||||||
NetworkedGameState, PairingRequestResponse, PairingStatusResponse, PlaceTokenResponse,
|
NetworkedGameState, PairingRequestResponse, PairingStatusResponse, PlaceTokenResponse,
|
||||||
PlacedEnum, SharedState, Turn,
|
PlacedEnum, SendEmoteRequestResponse, SharedState, Turn,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
@ -227,6 +227,46 @@ impl Component for ResetButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EmoteButton {}
|
||||||
|
|
||||||
|
enum EmoteButtonMsg {
|
||||||
|
Pressed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Properties)]
|
||||||
|
struct EmoteButtonProperties {
|
||||||
|
emote: EmoteEnum,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for EmoteButton {
|
||||||
|
type Message = EmoteButtonMsg;
|
||||||
|
type Properties = EmoteButtonProperties;
|
||||||
|
|
||||||
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let onclick = ctx.link().callback(|_| EmoteButtonMsg::Pressed);
|
||||||
|
let emote_id = format!("emote_{}", ctx.props().emote);
|
||||||
|
html! {
|
||||||
|
<button class={"emote"} id={emote_id} onclick={onclick}>
|
||||||
|
{ctx.props().emote.get_unicode()}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
ctx.link()
|
||||||
|
.get_parent()
|
||||||
|
.expect("Wrapper should be parent of EmoteButton")
|
||||||
|
.clone()
|
||||||
|
.downcast::<Wrapper>()
|
||||||
|
.send_message(WrapperMsg::SendEmote(ctx.props().emote));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Slot {}
|
pub struct Slot {}
|
||||||
|
|
||||||
pub enum SlotMessage {
|
pub enum SlotMessage {
|
||||||
|
@ -485,7 +525,11 @@ impl Wrapper {
|
||||||
_ => NetworkedGameState::InternalError,
|
_ => NetworkedGameState::InternalError,
|
||||||
};
|
};
|
||||||
|
|
||||||
WrapperMsg::BackendResponse(BREnum::GotStatus(networked_game_state, response.board))
|
WrapperMsg::BackendResponse(BREnum::GotStatus(
|
||||||
|
networked_game_state,
|
||||||
|
response.board,
|
||||||
|
response.peer_emote,
|
||||||
|
))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +695,8 @@ pub enum BREnum {
|
||||||
Error(String),
|
Error(String),
|
||||||
GotID(u32, Option<Turn>),
|
GotID(u32, Option<Turn>),
|
||||||
GotPairing(Option<Turn>),
|
GotPairing(Option<Turn>),
|
||||||
GotStatus(NetworkedGameState, Option<String>),
|
/// Second opt string is board_str, third opt string is received emote
|
||||||
|
GotStatus(NetworkedGameState, Option<String>, Option<String>),
|
||||||
GotPlaced(PlacedEnum, String),
|
GotPlaced(PlacedEnum, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,6 +712,8 @@ pub enum WrapperMsg {
|
||||||
BackendRequest { place: u8 },
|
BackendRequest { place: u8 },
|
||||||
BackendResponse(BREnum),
|
BackendResponse(BREnum),
|
||||||
Reset,
|
Reset,
|
||||||
|
SendEmote(EmoteEnum),
|
||||||
|
SentEmote(EmoteEnum),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WrapperMsg {
|
impl WrapperMsg {
|
||||||
|
@ -697,6 +744,12 @@ impl Component for Wrapper {
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<MainMenu />
|
<MainMenu />
|
||||||
<ResetButton />
|
<ResetButton />
|
||||||
|
<div class="emote_wrapper">
|
||||||
|
<EmoteButton emote={EmoteEnum::Smile} />
|
||||||
|
<EmoteButton emote={EmoteEnum::Neutral} />
|
||||||
|
<EmoteButton emote={EmoteEnum::Frown} />
|
||||||
|
<EmoteButton emote={EmoteEnum::Think} />
|
||||||
|
</div>
|
||||||
<Slot idx=0 state={shared.board[0].clone()} placed={shared.placed[0].clone()} />
|
<Slot idx=0 state={shared.board[0].clone()} placed={shared.placed[0].clone()} />
|
||||||
<Slot idx=1 state={shared.board[1].clone()} placed={shared.placed[1].clone()} />
|
<Slot idx=1 state={shared.board[1].clone()} placed={shared.placed[1].clone()} />
|
||||||
<Slot idx=2 state={shared.board[2].clone()} placed={shared.placed[2].clone()} />
|
<Slot idx=2 state={shared.board[2].clone()} placed={shared.placed[2].clone()} />
|
||||||
|
@ -1286,7 +1339,6 @@ impl Component for Wrapper {
|
||||||
let is_networked_multiplayer =
|
let is_networked_multiplayer =
|
||||||
shared.game_state.borrow().is_networked_multiplayer();
|
shared.game_state.borrow().is_networked_multiplayer();
|
||||||
if !self.do_backend_tick || !is_networked_multiplayer {
|
if !self.do_backend_tick || !is_networked_multiplayer {
|
||||||
// disconnect id if backend tick is to be stopped
|
|
||||||
self.send_disconnect();
|
self.send_disconnect();
|
||||||
self.cleanup_disconnect_callbacks();
|
self.cleanup_disconnect_callbacks();
|
||||||
return false;
|
return false;
|
||||||
|
@ -1444,7 +1496,41 @@ impl Component for Wrapper {
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BREnum::GotStatus(networked_game_state, board_opt) => {
|
BREnum::GotStatus(networked_game_state, board_opt, emote_opt) => {
|
||||||
|
let current_side = shared
|
||||||
|
.game_state
|
||||||
|
.borrow()
|
||||||
|
.get_networked_current_side()
|
||||||
|
.expect("Should be Networked mode");
|
||||||
|
if let Some(emote_string) = emote_opt {
|
||||||
|
if let Ok(emote_enum) = EmoteEnum::try_from(emote_string.as_str()) {
|
||||||
|
append_to_info_text(
|
||||||
|
&document,
|
||||||
|
"info_text0",
|
||||||
|
&format!(
|
||||||
|
"<b class=\"{}\">{} sent <b class=\"emote\">{}</p></b>",
|
||||||
|
current_side.get_opposite().get_color(),
|
||||||
|
current_side.get_opposite(),
|
||||||
|
emote_enum.get_unicode()
|
||||||
|
),
|
||||||
|
INFO_TEXT_MAX_ITEMS,
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
} else {
|
||||||
|
append_to_info_text(
|
||||||
|
&document,
|
||||||
|
"info_text0",
|
||||||
|
&format!(
|
||||||
|
"<b class=\"{}\">{} sent invalid emote</b>",
|
||||||
|
current_side.get_color(),
|
||||||
|
current_side.get_opposite()
|
||||||
|
),
|
||||||
|
INFO_TEXT_MAX_ITEMS,
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(board_string) = board_opt {
|
if let Some(board_string) = board_opt {
|
||||||
self.update_board_from_string(&shared, &document, board_string);
|
self.update_board_from_string(&shared, &document, board_string);
|
||||||
}
|
}
|
||||||
|
@ -1461,7 +1547,7 @@ impl Component for Wrapper {
|
||||||
&format!(
|
&format!(
|
||||||
"<b class=\"cyan\">It is CyanPlayer's ({}) Turn</b>",
|
"<b class=\"cyan\">It is CyanPlayer's ({}) Turn</b>",
|
||||||
if current_game_state
|
if current_game_state
|
||||||
.get_network_current_side()
|
.get_networked_current_side()
|
||||||
.unwrap_or(Turn::CyanPlayer)
|
.unwrap_or(Turn::CyanPlayer)
|
||||||
== Turn::CyanPlayer
|
== Turn::CyanPlayer
|
||||||
{
|
{
|
||||||
|
@ -1485,7 +1571,7 @@ impl Component for Wrapper {
|
||||||
"info_text1",
|
"info_text1",
|
||||||
&format!(
|
&format!(
|
||||||
"<b class=\"magenta\">It is MagentaPlayer's ({}) Turn</b>",
|
"<b class=\"magenta\">It is MagentaPlayer's ({}) Turn</b>",
|
||||||
if current_game_state.get_network_current_side().unwrap_or(Turn::CyanPlayer) == Turn::MagentaPlayer
|
if current_game_state.get_networked_current_side().unwrap_or(Turn::CyanPlayer) == Turn::MagentaPlayer
|
||||||
{
|
{
|
||||||
"your"
|
"your"
|
||||||
} else {
|
} else {
|
||||||
|
@ -1730,6 +1816,54 @@ impl Component for Wrapper {
|
||||||
self.do_backend_tick = false;
|
self.do_backend_tick = false;
|
||||||
self.cleanup_disconnect_callbacks();
|
self.cleanup_disconnect_callbacks();
|
||||||
}
|
}
|
||||||
|
WrapperMsg::SendEmote(emote) => {
|
||||||
|
if self.player_id.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let emote = emote;
|
||||||
|
let player_id = self.player_id.unwrap();
|
||||||
|
ctx.link().send_future(async move {
|
||||||
|
let mut json_entries = HashMap::new();
|
||||||
|
json_entries.insert("id".into(), format!("{}", player_id));
|
||||||
|
json_entries.insert("type".into(), "send_emote".into());
|
||||||
|
json_entries.insert("emote".into(), emote.to_string());
|
||||||
|
|
||||||
|
let send_to_backend_result = send_to_backend(json_entries).await;
|
||||||
|
if let Err(e) = send_to_backend_result {
|
||||||
|
return WrapperMsg::BackendResponse(BREnum::Error(format!("{:?}", e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let request_result: Result<SendEmoteRequestResponse, _> =
|
||||||
|
serde_json::from_str(&send_to_backend_result.unwrap());
|
||||||
|
if let Err(e) = request_result {
|
||||||
|
return WrapperMsg::BackendResponse(BREnum::Error(format!("{:?}", e)));
|
||||||
|
}
|
||||||
|
let response = request_result.unwrap();
|
||||||
|
|
||||||
|
if response.status.as_str() == "ok" {
|
||||||
|
WrapperMsg::SentEmote(emote)
|
||||||
|
} else {
|
||||||
|
WrapperMsg::BackendResponse(BREnum::Error(format!("{:?}", response.status)))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
WrapperMsg::SentEmote(emote) => {
|
||||||
|
let current_side_opt = shared.game_state.borrow().get_networked_current_side();
|
||||||
|
if let Some(current_side) = current_side_opt {
|
||||||
|
append_to_info_text(
|
||||||
|
&document,
|
||||||
|
"info_text0",
|
||||||
|
&format!(
|
||||||
|
"<b class=\"{}\">{} sent <b class=\"emote\">{}</p></b>",
|
||||||
|
current_side.get_color(),
|
||||||
|
current_side,
|
||||||
|
emote.get_unicode()
|
||||||
|
),
|
||||||
|
INFO_TEXT_MAX_ITEMS,
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
} // match (msg)
|
} // match (msg)
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
Loading…
Reference in a new issue