/// third bool is if cyan player
pub type CheckPairingType = (bool, bool, bool);
-/// second String is board string, third String is received emote type
-pub type BoardStateType = (DBGameState, Option<String>, Option<EmoteEnum>);
+/// second String is board string, third String is date updated, fourth value
+/// is EmoteEnum
+pub type BoardStateType = (
+ DBGameState,
+ Option<String>,
+ Option<String>,
+ Option<EmoteEnum>,
+);
pub type PlaceResultType = Result<(DBPlaceStatus, Option<String>), DBPlaceError>;
// don't stop server on send fail, may have timed out and
// dropped the receiver
response_sender
- .send((DBGameState::UnknownID, None, None))
+ .send((DBGameState::UnknownID, None, None, None))
.ok();
return false;
}
}
// TODO maybe handle "opponent_disconnected" case
- let row_result: Result<(String, i64, Option<u32>, Option<u32>), RusqliteError> = conn.query_row(
- "SELECT games.board, games.status, games.cyan_player, games.magenta_player FROM games JOIN players WHERE players.id = ? AND games.id = players.game_id;",
+ let row_result: Result<(String, i64, Option<u32>, Option<u32>, String), RusqliteError> = conn.query_row(
+ "SELECT games.board, games.status, games.cyan_player, games.magenta_player, games.turn_time_start FROM games JOIN players WHERE players.id = ? AND games.id = players.game_id;",
[player_id],
|row| {
let board_result = row.get(0);
let status_result = row.get(1);
let cyan_player = row.get(2);
let magenta_player = row.get(3);
- if board_result.is_ok() && status_result.is_ok() && cyan_player.is_ok() && magenta_player.is_ok() {
- if let (Ok(board), Ok(status), Ok(cyan_id), Ok(magenta_id)) = (board_result, status_result, cyan_player, magenta_player) {
- Ok((board, status, cyan_id, magenta_id))
+ let updated_time = row.get(4);
+ if board_result.is_ok() && status_result.is_ok() && cyan_player.is_ok() && magenta_player.is_ok() && updated_time.is_ok() {
+ if let (Ok(board), Ok(status), Ok(cyan_id), Ok(magenta_id), Ok(updated_time)) = (board_result, status_result, cyan_player, magenta_player, updated_time) {
+ Ok((board, status, cyan_id, magenta_id, updated_time))
} else {
- unreachable!("Both row items should be Ok");
+ unreachable!("All row items should be Ok");
}
} else if board_result.is_err() {
board_result
- .map(|_| (String::from("this value should never be returned"), 0, None, None))
+ .map(|_| (String::from("this value should never be returned"), 0, None, None, String::new()))
} else if status_result.is_err() {
status_result
- .map(|_| (String::from("this value should never be returned"), 0, None, None))
+ .map(|_| (String::from("this value should never be returned"), 0, None, None, String::new()))
} else if cyan_player.is_err() {
cyan_player
- .map(|_| (String::from("this value should never be returned"), 0, None, None))
- } else {
+ .map(|_| (String::from("this value should never be returned"), 0, None, None, String::new()))
+ } else if magenta_player.is_err() {
magenta_player
- .map(|_| (String::from("this value should never be returned"), 0, None, None))
+ .map(|_| (String::from("this value should never be returned"), 0, None, None, String::new()))
+ } else {
+ updated_time
+ .map(|_| (String::from("this value should never be returned"), 0, None, None, String::new()))
}
}
);
- if let Ok((board, status, cyan_opt, magenta_opt)) = row_result {
+ if let Ok((board, status, cyan_opt, magenta_opt, updated_time)) = row_result {
if board.len() != (ROWS * COLS) as usize {
// board is invalid size
- Ok((DBGameState::InternalError, None, received_emote))
+ Ok((
+ DBGameState::InternalError,
+ None,
+ Some(updated_time),
+ received_emote,
+ ))
} else if cyan_opt.is_none() || magenta_opt.is_none() {
// One player disconnected
self.disconnect_player(Some(conn), player_id).ok();
// Remove the game(s) with disconnected players
if self.clear_empty_games(Some(conn)).is_err() {
- Ok((DBGameState::InternalError, None, received_emote))
+ Ok((
+ DBGameState::InternalError,
+ None,
+ Some(updated_time),
+ received_emote,
+ ))
} else if status == 2 || status == 3 {
- Ok((DBGameState::from(status), Some(board), received_emote))
+ Ok((
+ DBGameState::from(status),
+ Some(board),
+ Some(updated_time),
+ received_emote,
+ ))
} else {
Ok((
DBGameState::OpponentDisconnected,
Some(board),
+ Some(updated_time),
received_emote,
))
}
} else {
// Game in progress, or other state depending on "status"
- Ok((DBGameState::from(status), Some(board), received_emote))
+ Ok((
+ DBGameState::from(status),
+ Some(board),
+ Some(updated_time),
+ received_emote,
+ ))
}
} else if let Err(RusqliteError::QueryReturnedNoRows) = row_result {
// No rows is either player doesn't exist or not paired
let (exists, is_paired, _is_cyan) =
self.check_if_player_is_paired(Some(conn), player_id)?;
if !exists {
- Ok((DBGameState::UnknownID, None, received_emote))
+ Ok((DBGameState::UnknownID, None, None, received_emote))
} else if !is_paired {
- Ok((DBGameState::NotPaired, None, received_emote))
+ Ok((DBGameState::NotPaired, None, None, received_emote))
} else {
unreachable!("either exists or is_paired must be false");
}
return Err("{\"type\":\"game_state\", \"status\":\"internal_error\"}".into());
}
- if let Ok((db_game_state, board_string_opt, received_emote_opt)) =
+ if let Ok((db_game_state, board_string_opt, updated_time_opt, received_emote_opt)) =
resp_rx.recv_timeout(DB_REQUEST_TIMEOUT)
{
if let Some(board_string) = board_string_opt {
+ let updated_time = if let Some(time_string) = updated_time_opt {
+ time_string
+ } else {
+ return Err("{\"type\":\"game_state\", \"status\":\"internal_error\"}".into());
+ };
+
if let Some(emote) = received_emote_opt {
Ok(format!(
- "{{\"type\":\"game_state\", \"status\":\"{}\", \"board\":\"{}\", \"peer_emote\": \"{}\"}}",
- db_game_state, board_string, emote
+ "{{\"type\":\"game_state\", \"status\":\"{}\", \"board\":\"{}\", \"peer_emote\": \"{}\", \"updated_time\": \"{}\"}}",
+ db_game_state, board_string, emote, updated_time
))
} else {
Ok(format!(
- "{{\"type\":\"game_state\", \"status\":\"{}\", \"board\":\"{}\"}}",
- db_game_state, board_string
+ "{{\"type\":\"game_state\", \"status\":\"{}\", \"board\":\"{}\", \"updated_time\": \"{}\"}}",
+ db_game_state, board_string, updated_time
))
}
} else {
place_request: Option<u8>,
do_backend_tick: bool,
cleanup_id_callback: Rc<RefCell<Option<Function>>>,
+ board_updated_time: Option<String>,
}
impl Wrapper {
_ => NetworkedGameState::InternalError,
};
- WrapperMsg::BackendResponse(BREnum::GotStatus(
+ WrapperMsg::BackendResponse(BREnum::GotStatus {
networked_game_state,
- response.board,
- response.peer_emote,
- ))
+ board_string: response.board,
+ received_emote: response.peer_emote,
+ updated_time: response.updated_time,
+ })
});
}
Error(String),
GotID(u32, Option<Turn>),
GotPairing(Option<Turn>),
- /// Second opt string is board_str, third opt string is received emote
- GotStatus(NetworkedGameState, Option<String>, Option<String>),
+ /// Second opt string is board_str, third opt string is received emote,
+ /// fourth opt string is updated_time
+ GotStatus {
+ networked_game_state: NetworkedGameState,
+ board_string: Option<String>,
+ received_emote: Option<String>,
+ updated_time: Option<String>,
+ },
GotPlaced(PlacedEnum, String),
}
place_request: None,
do_backend_tick: true,
cleanup_id_callback: Rc::new(RefCell::new(None)),
+ board_updated_time: None,
}
}
.ok();
}
}
- BREnum::GotStatus(networked_game_state, board_opt, emote_opt) => {
+ BREnum::GotStatus {
+ networked_game_state,
+ board_string,
+ received_emote,
+ updated_time,
+ } => {
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 Some(emote_string) = received_emote {
if let Ok(emote_enum) = EmoteEnum::try_from(emote_string.as_str()) {
append_to_info_text(
&document,
}
}
- if let Some(board_string) = board_opt {
- self.update_board_from_string(&shared, &document, board_string);
+ // only update board string if updated_time is different
+ if self.board_updated_time != updated_time {
+ if let Some(updated_time) = updated_time {
+ self.board_updated_time.replace(updated_time);
+ if let Some(board_string) = board_string {
+ self.update_board_from_string(&shared, &document, board_string);
+ }
+ }
}
let mut current_game_state: GameState = shared.game_state.borrow().clone();