Commit a1fb5c7a authored by 陈冲's avatar 陈冲

feat: 已上榜玩家当天重玩已上榜的游戏不再显示

parent aa23cfba
drop table if exists tb_room;
create table tb_room
(
batch_no VARCHAR(50) PRIMARY KEY, -- 批次
item_num int not null check (item_num between 1 and 6), -- 游戏项目(1到6)
player_count int not null default 0, -- 房间人数
create_date timestamptz -- 创建时间
);
drop table if exists tb_game; drop table if exists tb_game;
create table tb_game create table tb_game
( (
......
DROP TABLE IF EXISTS tb_room;
CREATE TABLE tb_room
(
batch_no VARCHAR(50) PRIMARY KEY,
item_num INT NOT NULL,
player_count INT NOT NULL DEFAULT 0,
create_date DATETIME
);
DROP TABLE IF EXISTS tb_game; DROP TABLE IF EXISTS tb_game;
CREATE TABLE tb_game CREATE TABLE tb_game
( (
......
...@@ -2,7 +2,7 @@ use crate::{ ...@@ -2,7 +2,7 @@ use crate::{
commons::utils::CONFIG as config, commons::utils::CONFIG as config,
db::models::{get_i32, get_string, log::Log}, db::models::{get_i32, get_string, log::Log},
}; };
use chrono::{DateTime, NaiveDate, Utc}; use chrono::{DateTime, Utc};
use serde_json::json; use serde_json::json;
pub struct Game { pub struct Game {
...@@ -65,16 +65,22 @@ impl Game { ...@@ -65,16 +65,22 @@ impl Game {
} }
} }
} }
pub async fn get_rank(wechat_id: &str) -> i32 { pub async fn get_rank(wechat_id: &str, item_num: i32) -> i32 {
let Some(_) = &config.db else { let Some(_) = &config.db else {
println!("没有配置数据库, get_rank return 0;"); println!("没有配置数据库, get_rank return 0;");
return 0; return 0;
}; };
let res = crate::db::db_query( let res = crate::db::db_query(
r#"SELECT COUNT(1) AS rank_count FROM tb_game WHERE wechat_id = ? r#"SELECT COUNT(1) AS rank_count
AND game_rank <= 10"#, FROM tb_game g
vec![json!(&wechat_id)], INNER JOIN tb_room r ON r.batch_no = g.batch_no
WHERE g.wechat_id = ?
AND g.item_num = ?
AND r.item_num = ?
AND g.game_rank BETWEEN 1 AND 10
AND DATE(r.create_date) = CURRENT_DATE"#,
vec![json!(&wechat_id), json!(item_num), json!(item_num)],
) )
.await; .await;
match res { match res {
......
...@@ -3,6 +3,7 @@ use serde_json::Value; ...@@ -3,6 +3,7 @@ use serde_json::Value;
pub mod game; pub mod game;
pub mod log; pub mod log;
pub mod manager; pub mod manager;
pub mod room;
pub fn get_i32(row: &Value, key: &str) -> Result<i32, String> { pub fn get_i32(row: &Value, key: &str) -> Result<i32, String> {
row.get(key) row.get(key)
......
use crate::commons::utils::CONFIG as config;
use chrono::{DateTime, Utc};
use serde_json::json;
pub struct GameRoom {
pub batch_no: String,
pub item_num: i32,
pub player_count: i32,
pub create_date: Option<DateTime<Utc>>,
}
impl GameRoom {
pub async fn insert(&self) -> bool {
let Some(_) = &config.db else {
println!("没有配置数据库, room insert return true;");
return true;
};
let res = crate::db::db_query(
r#"insert into tb_room(batch_no,item_num,player_count,create_date) values(?,?,?,now());"#,
vec![
json!(&self.batch_no),
json!(&self.item_num),
json!(&self.player_count),
],
)
.await;
match res {
Ok(_) => true,
Err(err) => {
println!("room insert failed: {err}");
false
}
}
}
}
...@@ -2,6 +2,7 @@ use crate::commons::utils::{self, CONFIG as config}; ...@@ -2,6 +2,7 @@ use crate::commons::utils::{self, CONFIG as config};
use crate::db::models::game::Game; use crate::db::models::game::Game;
use crate::db::models::log::Log; use crate::db::models::log::Log;
use crate::db::models::manager::*; use crate::db::models::manager::*;
use crate::db::models::room::GameRoom;
use bytes::Bytes; use bytes::Bytes;
use dashmap::DashMap; use dashmap::DashMap;
use dashmap::mapref::entry::Entry; use dashmap::mapref::entry::Entry;
...@@ -95,6 +96,7 @@ struct RoomState { ...@@ -95,6 +96,7 @@ struct RoomState {
players: HashMap<String, RoomPlayer>, // 玩家列表,key 是 userid players: HashMap<String, RoomPlayer>, // 玩家列表,key 是 userid
next_entry_order: usize, next_entry_order: usize,
current_game_id: Option<String>, current_game_id: Option<String>,
current_item_num: i32,
batch_no: String, batch_no: String,
round_started_at: Option<Instant>, round_started_at: Option<Instant>,
} }
...@@ -262,6 +264,8 @@ impl RoomState { ...@@ -262,6 +264,8 @@ impl RoomState {
self.players.clear(); self.players.clear();
self.next_entry_order = 0; self.next_entry_order = 0;
self.current_game_id = None; self.current_game_id = None;
self.current_item_num = 0;
self.batch_no.clear();
self.round_started_at = None; self.round_started_at = None;
} }
} }
...@@ -320,6 +324,15 @@ fn valid_user(userid: &str, validuser: &str) -> bool { ...@@ -320,6 +324,15 @@ fn valid_user(userid: &str, validuser: &str) -> bool {
} }
} }
fn parse_item_num(game_id: &str) -> i32 {
game_id
.trim()
.strip_prefix("game")
.unwrap_or_else(|| game_id.trim())
.parse::<i32>()
.unwrap_or(0)
}
fn decode_msgpack(data: &Data<Bytes>) -> Result<Value, rmp_serde::decode::Error> { fn decode_msgpack(data: &Data<Bytes>) -> Result<Value, rmp_serde::decode::Error> {
rmp_serde::from_slice(data.0.as_ref()) rmp_serde::from_slice(data.0.as_ref())
} }
...@@ -677,6 +690,7 @@ async fn handle_room_command( ...@@ -677,6 +690,7 @@ async fn handle_room_command(
} }
state.reset(); state.reset();
state.current_game_id = Some(game_id); state.current_game_id = Some(game_id);
state.current_item_num = index as i32;
state.status = RoomStatus::Loading; state.status = RoomStatus::Loading;
// let snapshot = state.snapshot(); // let snapshot = state.snapshot();
drop(state); drop(state);
...@@ -712,10 +726,8 @@ async fn handle_room_command( ...@@ -712,10 +726,8 @@ async fn handle_room_command(
.and_then(|value| value.as_str()) .and_then(|value| value.as_str())
.unwrap_or("") .unwrap_or("")
.to_string(); .to_string();
let already_top_ranked = CLIENT_TOP_RANKED_MAP let already_top_ranked = Game::get_rank(userid, parse_item_num(&gameId)).await > 0;
.get(userid) CLIENT_TOP_RANKED_MAP.insert(userid.to_string(), already_top_ranked);
.map(|value| *value)
.unwrap_or(false);
if let Ok(mut state) = ROOM_STATE.lock() { if let Ok(mut state) = ROOM_STATE.lock() {
// 当前h5进入的不是大屏开启的游戏房间 // 当前h5进入的不是大屏开启的游戏房间
...@@ -809,7 +821,7 @@ async fn handle_room_command( ...@@ -809,7 +821,7 @@ async fn handle_room_command(
return; return;
} }
let game_index = data.as_str().unwrap_or(""); let game_index = data.as_str().unwrap_or("");
if let Ok(mut state) = ROOM_STATE.lock() { let start_info = if let Ok(mut state) = ROOM_STATE.lock() {
if state.players.is_empty() { if state.players.is_empty() {
drop(state); drop(state);
emit_msgpack(&socket, evt, &err_resp("房间中没有玩家", Some(json!(1)))); emit_msgpack(&socket, evt, &err_resp("房间中没有玩家", Some(json!(1))));
...@@ -823,16 +835,46 @@ async fn handle_room_command( ...@@ -823,16 +835,46 @@ async fn handle_room_command(
state.status = RoomStatus::Running; state.status = RoomStatus::Running;
state.current_game_id = Some(game_index.to_string()); state.current_game_id = Some(game_index.to_string());
if state.current_item_num <= 0 {
state.current_item_num = parse_item_num(game_index);
}
state.round_started_at = Some(Instant::now()); state.round_started_at = Some(Instant::now());
let round_id = GAME_ROUND_ID.fetch_add(1, Ordering::SeqCst) + 1; let round_id = GAME_ROUND_ID.fetch_add(1, Ordering::SeqCst) + 1;
// let snapshot = state.snapshot(); // let snapshot = state.snapshot();
let play_len = state.players.len(); let play_len = state.players.len();
let item_num = state.current_item_num;
//每次开始房间时记录当前批次 //每次开始房间时记录当前批次
let batch_no = format!("{}-{}", utils::get_current_timestamp(), play_len); let batch_no = format!("{}-{}", utils::get_current_timestamp(), play_len);
state.batch_no = batch_no.clone(); state.batch_no = batch_no.clone();
drop(state); Some((round_id, batch_no, item_num, play_len))
//通知所有玩家倒计时60秒,实际上还有3秒倒计时,以前2秒统计结果,所以是65 //通知所有玩家倒计时60秒,实际上还有3秒倒计时,以前2秒统计结果,所以是65
} else {
None
};
let Some((round_id, batch_no, item_num, play_len)) = start_info else {
return;
};
{
let room = GameRoom {
batch_no: batch_no.clone(),
item_num,
player_count: play_len as i32,
create_date: None,
};
if !room.insert().await {
if let Ok(mut state) = ROOM_STATE.lock() {
if state.batch_no == batch_no {
state.status = RoomStatus::Loading;
state.batch_no.clear();
state.round_started_at = None;
}
}
emit_msgpack(&socket, evt, &err_resp("房间批次保存失败", None));
return;
}
spawn_game_timeout( spawn_game_timeout(
round_id, round_id,
GAME_START_COUNTDOWN_SECS + GAME_RUNNING_SECS + GAME_RESULT_WAIT_SECS, GAME_START_COUNTDOWN_SECS + GAME_RUNNING_SECS + GAME_RESULT_WAIT_SECS,
...@@ -989,6 +1031,11 @@ async fn handle_room_command( ...@@ -989,6 +1031,11 @@ async fn handle_room_command(
if game.insert().await { if game.insert().await {
if !already_top_ranked && (1..=ROOM_SCORE_RANK_LIMIT as i64).contains(&rank) { if !already_top_ranked && (1..=ROOM_SCORE_RANK_LIMIT as i64).contains(&rank) {
CLIENT_TOP_RANKED_MAP.insert(userid.to_string(), true); CLIENT_TOP_RANKED_MAP.insert(userid.to_string(), true);
if let Ok(mut state) = ROOM_STATE.lock() {
if let Some(player) = state.players.get_mut(userid) {
player.already_top_ranked = true;
}
}
} }
let mut payload = json!({ let mut payload = json!({
...@@ -1126,8 +1173,7 @@ pub async fn on_connect(_io: SocketIo, socket: SocketRef, Data(data): Data<Value ...@@ -1126,8 +1173,7 @@ pub async fn on_connect(_io: SocketIo, socket: SocketRef, Data(data): Data<Value
} }
} }
} else { } else {
let already_top_ranked = Game::get_rank(&userid).await > 0; CLIENT_TOP_RANKED_MAP.insert(userid.clone(), false);
CLIENT_TOP_RANKED_MAP.insert(userid.clone(), already_top_ranked);
if get_admin_count() == 0 { if get_admin_count() == 0 {
match CLIENT_PLAYER_MAP.entry(userid.clone()) { match CLIENT_PLAYER_MAP.entry(userid.clone()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment