diff --git a/src/api/attack/mod.rs b/src/api/attack/mod.rs index 171183db..7e8ba304 100644 --- a/src/api/attack/mod.rs +++ b/src/api/attack/mod.rs @@ -43,9 +43,10 @@ async fn init_attack( pool: web::Data, redis_pool: Data, user: AuthUser, + is_self: web::Query>, ) -> Result { let attacker_id = user.0; - + let is_self_attack = *is_self.get("is_self").unwrap_or(&false); log::info!("Attacker:{} is trying to initiate an attack", attacker_id); let mut conn = pool.get().map_err(|err| error::handle_error(err.into()))?; if let Ok(check) = util::can_attack_happen(&mut conn, attacker_id, true) { @@ -71,22 +72,27 @@ async fn init_attack( .get() .map_err(|err| error::handle_error(err.into()))?; - let random_opponent_id = web::block(move || { - Ok(util::get_random_opponent_id( - attacker_id, - &mut conn, - redis_conn, - )?) as anyhow::Result> - }) - .await? - .map_err(|err| error::handle_error(err.into()))?; - - let opponent_id = if let Some(id) = random_opponent_id { - id + let opponent_id: i32; + if is_self_attack { + opponent_id = attacker_id; } else { - log::info!("No opponent found for Attacker:{}", attacker_id); - return Err(ErrorBadRequest("No opponent found")); - }; + let random_opponent_id = web::block(move || { + Ok(util::get_random_opponent_id( + attacker_id, + &mut conn, + redis_conn, + )?) as anyhow::Result> + }) + .await? + .map_err(|err| error::handle_error(err.into()))?; + + opponent_id = if let Some(id) = random_opponent_id { + id + } else { + log::info!("No opponent found for Attacker:{}", attacker_id); + return Err(ErrorBadRequest("No opponent found")); + }; + } log::info!( "Opponent:{} found for Attacker:{}", @@ -136,10 +142,10 @@ async fn init_attack( log::info!("User details fetched for Opponent:{}", opponent_id); - //Create game + //Create a new game let mut conn = pool.get().map_err(|err| error::handle_error(err.into()))?; let game_id = web::block(move || { - Ok(util::add_game(attacker_id, opponent_id, map_id, &mut conn)?) as anyhow::Result + Ok(util::add_game(attacker_id, opponent_id, map_id, &mut conn, is_self_attack)?) as anyhow::Result }) .await? .map_err(|err| error::handle_error(err.into()))?; @@ -199,6 +205,12 @@ async fn socket_handler( let query_params = req.query_string().split('&').collect::>(); let user_token = query_params[0].split('=').collect::>()[1]; let attack_token = query_params[1].split('=').collect::>()[1]; + let is_self_attack = query_params[2] + .split('=') + .collect::>() + .get(1) + .map(|&s| s == "true") + .unwrap_or(false); let attacker_id = util::decode_user_token(user_token).map_err(|err| error::handle_error(err.into()))?; @@ -224,9 +236,16 @@ async fn socket_handler( } let defender_id = attack_token_data.defender_id; - if attacker_id == defender_id { - log::info!("Attacker:{} is trying to attack himself", attacker_id); - return Err(ErrorBadRequest("Can't attack yourself")); + if !is_self_attack { + if attacker_id == defender_id { + log::info!("Attacker:{} is trying to attack himself", attacker_id); + return Err(ErrorBadRequest("Can't attack yourself")); + } + } else { + if attacker_id != defender_id { + log::info!("Attacker:{} is trying to attack someone else", attacker_id); + return Err(ErrorBadRequest("Can't attack someone else")); + } } let mut redis_conn = redis_pool @@ -487,6 +506,7 @@ async fn socket_handler( &mut conn, &damaged_base_items.buildings_damaged, &mut redis_conn, + is_self_attack, ) .is_err() { @@ -586,6 +606,7 @@ async fn socket_handler( &mut conn, &damaged_base_items.buildings_damaged, &mut redis_conn, + is_self_attack, ) .is_err() { diff --git a/src/api/attack/util.rs b/src/api/attack/util.rs index baa3c4c9..832bc59a 100644 --- a/src/api/attack/util.rs +++ b/src/api/attack/util.rs @@ -143,6 +143,7 @@ pub fn add_game( defender_id: i32, map_layout_id: i32, conn: &mut PgConnection, + is_self_attack: bool, ) -> Result { use crate::schema::game; @@ -160,8 +161,9 @@ pub fn add_game( is_game_over: &false, date: &chrono::Local::now().date_naive(), }; - - let inserted_game: Game = diesel::insert_into(game::table) + let inserted_game: Game; + if !is_self_attack { + inserted_game = diesel::insert_into(game::table) .values(&new_game) .get_result(conn) .map_err(|err| DieselError { @@ -169,8 +171,10 @@ pub fn add_game( function: function!(), error: err, })?; - - Ok(inserted_game.id) + Ok(inserted_game.id) + } else { + Ok(-1) + } } pub fn fetch_attack_history( @@ -825,28 +829,29 @@ pub fn terminate_game( conn: &mut PgConnection, damaged_buildings: &[BuildingDamageResponse], redis_conn: &mut RedisConn, + is_self_attack: bool, ) -> Result<()> { - use crate::schema::{artifact, game}; let attacker_id = game_log.a.id; let defender_id = game_log.d.id; - let damage_done = game_log.r.d; - let bombs_used = game_log.r.b; - let artifacts_collected = game_log.r.a; let game_id = game_log.g; - log::info!( - "Terminating game for game:{} and attacker:{} and opponent:{}", - game_id, - attacker_id, - defender_id - ); - - let (attack_score, defense_score) = if damage_done < WIN_THRESHOLD { - (damage_done - 100, 100 - damage_done) - } else { - (damage_done, -damage_done) - }; + if !is_self_attack { + use crate::schema::{artifact, game}; + let damage_done = game_log.r.d; + let bombs_used = game_log.r.b; + let artifacts_collected = game_log.r.a; + log::info!( + "Terminating game for game:{} and attacker:{} and opponent:{}", + game_id, + attacker_id, + defender_id + ); - let attacker_details = user::table + let (attack_score, defense_score) = if damage_done < WIN_THRESHOLD { + (damage_done - 100, 100 - damage_done) + } else { + (damage_done, -damage_done) + }; + let attacker_details = user::table .filter(user::id.eq(attacker_id)) .first::(conn) .map_err(|err| DieselError { @@ -855,102 +860,102 @@ pub fn terminate_game( error: err, })?; - let defender_details = user::table - .filter(user::id.eq(defender_id)) - .first::(conn) - .map_err(|err| DieselError { - table: "game", - function: function!(), - error: err, - })?; - - let attack_score = attack_score as f32 / 100_f32; - let defence_score = defense_score as f32 / 100_f32; + let defender_details = user::table + .filter(user::id.eq(defender_id)) + .first::(conn) + .map_err(|err| DieselError { + table: "game", + function: function!(), + error: err, + })?; - let new_trophies = new_rating( - attacker_details.trophies, - defender_details.trophies, - attack_score, - defence_score, - ); + let attack_score = attack_score as f32 / 100_f32; + let defence_score = defense_score as f32 / 100_f32; - //Add bonus trophies (just call the function) - - game_log.r.oa = attacker_details.trophies; - game_log.r.od = defender_details.trophies; - game_log.r.na = new_trophies.0; - game_log.r.nd = new_trophies.1; - - diesel::update(game::table.find(game_id)) - .set(( - game::damage_done.eq(damage_done), - game::is_game_over.eq(true), - game::emps_used.eq(bombs_used), - game::attack_score.eq(new_trophies.0 - attacker_details.trophies), - game::defend_score.eq(new_trophies.1 - defender_details.trophies), - game::artifacts_collected.eq(artifacts_collected), - )) - .execute(conn) - .map_err(|err| DieselError { - table: "game", - function: function!(), - error: err, - })?; + let new_trophies = new_rating( + attacker_details.trophies, + defender_details.trophies, + attack_score, + defence_score, + ); - let (attacker_wins, defender_wins) = if damage_done < WIN_THRESHOLD { - (0, 1) - } else { - (1, 0) - }; + //Add bonus trophies (just call the function) + + game_log.r.oa = attacker_details.trophies; + game_log.r.od = defender_details.trophies; + game_log.r.na = new_trophies.0; + game_log.r.nd = new_trophies.1; + + diesel::update(game::table.find(game_id)) + .set(( + game::damage_done.eq(damage_done), + game::is_game_over.eq(true), + game::emps_used.eq(bombs_used), + game::attack_score.eq(new_trophies.0 - attacker_details.trophies), + game::defend_score.eq(new_trophies.1 - defender_details.trophies), + game::artifacts_collected.eq(artifacts_collected), + )) + .execute(conn) + .map_err(|err| DieselError { + table: "game", + function: function!(), + error: err, + })?; - diesel::update(user::table.find(&game_log.a.id)) - .set(( - user::artifacts.eq(user::artifacts + artifacts_collected), - user::trophies.eq(user::trophies + new_trophies.0 - attacker_details.trophies), - user::attacks_won.eq(user::attacks_won + attacker_wins), - )) - .execute(conn) - .map_err(|err| DieselError { - table: "game", - function: function!(), - error: err, - })?; + let (attacker_wins, defender_wins) = if damage_done < WIN_THRESHOLD { + (0, 1) + } else { + (1, 0) + }; - if deduct_artifacts_from_building(damaged_buildings.to_vec(), conn).is_err() { - log::info!( - "Failed to deduct artifacts from building for game:{} and attacker:{} and opponent:{}", - game_id, - attacker_id, - defender_id - ); - } - diesel::update(user::table.find(&game_log.d.id)) - .set(( - user::artifacts.eq(user::artifacts - artifacts_collected), - user::trophies.eq(user::trophies + new_trophies.1 - defender_details.trophies), - user::defenses_won.eq(user::defenses_won + defender_wins), - )) - .execute(conn) - .map_err(|err| DieselError { - table: "game", - function: function!(), - error: err, - })?; + diesel::update(user::table.find(&game_log.a.id)) + .set(( + user::artifacts.eq(user::artifacts + artifacts_collected), + user::trophies.eq(user::trophies + new_trophies.0 - attacker_details.trophies), + user::attacks_won.eq(user::attacks_won + attacker_wins), + )) + .execute(conn) + .map_err(|err| DieselError { + table: "game", + function: function!(), + error: err, + })?; - let attacker_map_id = get_user_map_id(attacker_id, conn)?; - let attacker_bank_block_type_id = get_block_id_of_bank(conn, &attacker_id)?; - let attacker_bank_map_space_id = - get_bank_map_space_id(conn, &attacker_map_id, &attacker_bank_block_type_id)?; + if deduct_artifacts_from_building(damaged_buildings.to_vec(), conn).is_err() { + log::info!( + "Failed to deduct artifacts from building for game:{} and attacker:{} and opponent:{}", + game_id, + attacker_id, + defender_id + ); + } + diesel::update(user::table.find(&game_log.d.id)) + .set(( + user::artifacts.eq(user::artifacts - artifacts_collected), + user::trophies.eq(user::trophies + new_trophies.1 - defender_details.trophies), + user::defenses_won.eq(user::defenses_won + defender_wins), + )) + .execute(conn) + .map_err(|err| DieselError { + table: "game", + function: function!(), + error: err, + })?; - diesel::update(artifact::table.find(attacker_bank_map_space_id)) - .set(artifact::count.eq(artifact::count + artifacts_collected)) - .execute(conn) - .map_err(|err| DieselError { - table: "artifact", - function: function!(), - error: err, - })?; + let attacker_map_id = get_user_map_id(attacker_id, conn)?; + let attacker_bank_block_type_id = get_block_id_of_bank(conn, &attacker_id)?; + let attacker_bank_map_space_id = + get_bank_map_space_id(conn, &attacker_map_id, &attacker_bank_block_type_id)?; + diesel::update(artifact::table.find(attacker_bank_map_space_id)) + .set(artifact::count.eq(artifact::count + artifacts_collected)) + .execute(conn) + .map_err(|err| DieselError { + table: "artifact", + function: function!(), + error: err, + })?; + } // if let Ok(sim_log) = serde_json::to_string(&game_log) { // let new_simulation_log = NewSimulationLog { // game_id: &game_id,