diff --git a/planetwars-server/src/db/maps.rs b/planetwars-server/src/db/maps.rs index c9f50a0..dffe4fd 100644 --- a/planetwars-server/src/db/maps.rs +++ b/planetwars-server/src/db/maps.rs @@ -1,4 +1,4 @@ -use diesel::{PgConnection, QueryDsl, QueryResult, RunQueryDsl}; +use diesel::prelude::*; use crate::schema::maps; @@ -26,6 +26,10 @@ pub fn find_map(id: i32, conn: &PgConnection) -> QueryResult { maps::table.find(id).get_result(conn) } +pub fn find_map_by_name(name: &str, conn: &PgConnection) -> QueryResult { + maps::table.filter(maps::name.eq(name)).first(conn) +} + pub fn list_maps(conn: &PgConnection) -> QueryResult> { maps::table.get_results(conn) -} \ No newline at end of file +} diff --git a/planetwars-server/src/db/matches.rs b/planetwars-server/src/db/matches.rs index e2db0c1..86939be 100644 --- a/planetwars-server/src/db/matches.rs +++ b/planetwars-server/src/db/matches.rs @@ -21,6 +21,7 @@ pub struct NewMatch<'a> { pub state: MatchState, pub log_path: &'a str, pub is_public: bool, + pub map_id: Option, } #[derive(Insertable)] diff --git a/planetwars-server/src/modules/client_api.rs b/planetwars-server/src/modules/client_api.rs index f960e1b..0efc000 100644 --- a/planetwars-server/src/modules/client_api.rs +++ b/planetwars-server/src/modules/client_api.rs @@ -111,15 +111,20 @@ impl pb::client_api_service_server::ClientApiService for ClientApiServer { db::bots::find_bot_with_version_by_name(&match_request.opponent_name, &conn) .map_err(|_| Status::not_found("opponent not found"))?; + // TODO: allow map as parameter here + let map = db::maps::find_map_by_name(&"hex", &conn) + .map_err(|_| Status::not_found("map not found"))?; + let player_key = gen_alphanumeric(32); let remote_bot_spec = Box::new(RemoteBotSpec { player_key: player_key.clone(), router: self.router.clone(), }); - let run_match = RunMatch::from_players( + let run_match = RunMatch::new( self.runner_config.clone(), false, + map, vec![ MatchPlayer::BotSpec { spec: remote_bot_spec, diff --git a/planetwars-server/src/modules/matches.rs b/planetwars-server/src/modules/matches.rs index 3826abd..ecc7976 100644 --- a/planetwars-server/src/modules/matches.rs +++ b/planetwars-server/src/modules/matches.rs @@ -7,6 +7,7 @@ use tokio::task::JoinHandle; use crate::{ db::{ self, + maps::Map, matches::{MatchData, MatchResult}, }, util::gen_alphanumeric, @@ -18,6 +19,10 @@ pub struct RunMatch { players: Vec, config: Arc, is_public: bool, + // Map is mandatory for now. + // It would be nice to allow "anonymous" (eg. randomly generated) maps + // in the future, too. + map: Map, } pub enum MatchPlayer { @@ -32,9 +37,10 @@ pub enum MatchPlayer { impl RunMatch { // TODO: create a MatchParams struct - pub fn from_players( + pub fn new( config: Arc, is_public: bool, + map: Map, players: Vec, ) -> Self { let log_file_name = format!("{}.log", gen_alphanumeric(16)); @@ -43,13 +49,14 @@ impl RunMatch { log_file_name, players, is_public, + map, } } fn into_runner_config(self) -> runner::MatchConfig { runner::MatchConfig { - map_path: PathBuf::from(&self.config.maps_directory).join("hex.json"), - map_name: "hex".to_string(), + map_path: PathBuf::from(&self.config.maps_directory).join(self.map.file_path), + map_name: self.map.name, log_path: PathBuf::from(&self.config.match_logs_directory).join(&self.log_file_name), players: self .players @@ -88,6 +95,7 @@ impl RunMatch { state: db::matches::MatchState::Playing, log_path: &self.log_file_name, is_public: self.is_public, + map_id: Some(self.map.id), }; let new_match_players = self .players diff --git a/planetwars-server/src/modules/ranking.rs b/planetwars-server/src/modules/ranking.rs index dff3a72..7661b71 100644 --- a/planetwars-server/src/modules/ranking.rs +++ b/planetwars-server/src/modules/ranking.rs @@ -1,4 +1,5 @@ use crate::db::bots::BotVersion; +use crate::db::maps::Map; use crate::{db::bots::Bot, DbPool, GlobalConfig}; use crate::db; @@ -15,6 +16,8 @@ use tokio; const RANKER_INTERVAL: u64 = 60; const RANKER_NUM_MATCHES: i64 = 10_000; +const RANKER_MAP_NAME: &str = "hex"; + pub async fn run_ranker(config: Arc, db_pool: DbPool) { // TODO: make this configurable // play at most one match every n seconds @@ -25,7 +28,7 @@ pub async fn run_ranker(config: Arc, db_pool: DbPool) { .expect("could not get database connection"); loop { interval.tick().await; - let bots = db::bots::all_active_bots_with_version(&db_conn).unwrap(); + let bots = db::bots::all_active_bots_with_version(&db_conn).expect("could not load bots"); if bots.len() < 2 { // not enough bots to play a match continue; @@ -34,13 +37,17 @@ pub async fn run_ranker(config: Arc, db_pool: DbPool) { let mut rng = &mut rand::thread_rng(); bots.choose_multiple(&mut rng, 2).cloned().collect() }; - play_ranking_match(config.clone(), selected_bots, db_pool.clone()).await; + + let map = + db::maps::find_map_by_name(RANKER_MAP_NAME, &db_conn).expect("could not load map"); + play_ranking_match(config.clone(), map, selected_bots, db_pool.clone()).await; recalculate_ratings(&db_conn).expect("could not recalculate ratings"); } } async fn play_ranking_match( config: Arc, + map: Map, selected_bots: Vec<(Bot, BotVersion)>, db_pool: DbPool, ) { @@ -53,7 +60,7 @@ async fn play_ranking_match( players.push(player); } - let (_, handle) = RunMatch::from_players(config, true, players) + let (_, handle) = RunMatch::new(config, true, map, players) .run(db_pool.clone()) .await .expect("failed to run match"); diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs index 99b62d6..1ec8825 100644 --- a/planetwars-server/src/routes/demo.rs +++ b/planetwars-server/src/routes/demo.rs @@ -14,12 +14,13 @@ use serde::{Deserialize, Serialize}; use super::matches::ApiMatch; const DEFAULT_OPPONENT_NAME: &str = "simplebot"; +const DEFAULT_MAP_NAME: &str = "hex"; #[derive(Serialize, Deserialize, Debug)] pub struct SubmitBotParams { pub code: String, - // TODO: would it be better to pass an ID here? pub opponent_name: Option, + pub map_name: Option, } #[derive(Serialize, Deserialize)] @@ -40,17 +41,24 @@ pub async fn submit_bot( .opponent_name .unwrap_or_else(|| DEFAULT_OPPONENT_NAME.to_string()); + let map_name = params + .map_name + .unwrap_or_else(|| DEFAULT_MAP_NAME.to_string()); + let (opponent_bot, opponent_bot_version) = db::bots::find_bot_with_version_by_name(&opponent_name, &conn) .map_err(|_| StatusCode::BAD_REQUEST)?; + let map = db::maps::find_map_by_name(&map_name, &conn).map_err(|_| StatusCode::BAD_REQUEST)?; + let player_bot_version = save_code_string(¶ms.code, None, &conn, &config) // TODO: can we recover from this? .expect("could not save bot code"); - let run_match = RunMatch::from_players( + let run_match = RunMatch::new( config, false, + map.clone(), vec![ MatchPlayer::BotVersion { bot: None, @@ -82,8 +90,7 @@ pub async fn submit_bot( bot: Some(opponent_bot), }, ], - // TODO! - map: None, + map: Some(map), }; let api_match = super::matches::match_data_to_api(full_match_data);