mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add configurable team selection for #44
This commit is contained in:
@@ -126,10 +126,18 @@ pub struct QueueHandler {
|
||||
change_strategy: GamemodeChangeStrategy,
|
||||
autostart_after: Option<std::time::Duration>,
|
||||
autostart_task_started: std::sync::atomic::AtomicBool,
|
||||
team_choosers: std::sync::Arc<crate::team_selection::InitedTeamChoosers>,
|
||||
}
|
||||
|
||||
impl QueueHandler {
|
||||
pub fn new(conf: &oj_rc_core::ConfigImpl, game_host: &str, factory: std::sync::Arc<oj_rc_core::factory::Factory>, cpu_counter: std::sync::Arc<oj_rc_core::cubes::CpuListParser>, weapon_guesser: std::sync::Arc<oj_rc_core::cubes::WeaponListParser>,) -> Self {
|
||||
pub fn new(
|
||||
conf: &oj_rc_core::ConfigImpl,
|
||||
game_host: &str,
|
||||
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||
cpu_counter: std::sync::Arc<oj_rc_core::cubes::CpuListParser>,
|
||||
weapon_guesser: std::sync::Arc<oj_rc_core::cubes::WeaponListParser>,
|
||||
team_choosers: crate::team_selection::InitedTeamChoosers,
|
||||
) -> Self {
|
||||
let (domain, port_str) = game_host.split_once(':').expect("Invalid redirect address (must be domain:port)");
|
||||
let mp_settings = oj_rc_core::ConfigProvider::<()>::multiplayer_settings(conf);
|
||||
Self {
|
||||
@@ -147,6 +155,7 @@ impl QueueHandler {
|
||||
change_strategy: GamemodeChangeStrategy::from_core(<oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::server_config(conf).queue_mode),
|
||||
autostart_after: mp_settings.lobby_autostart_after,
|
||||
autostart_task_started: std::sync::atomic::AtomicBool::new(false),
|
||||
team_choosers: std::sync::Arc::new(team_choosers),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +173,7 @@ impl QueueHandler {
|
||||
let cpu_counter = self.cpu_counter.clone();
|
||||
let weapon_guesser = self.weapon_guesser.clone();
|
||||
let autostart_after = self.autostart_after.unwrap();
|
||||
let team_choosers = self.team_choosers.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
@@ -228,6 +238,7 @@ impl QueueHandler {
|
||||
key,
|
||||
q_entry,
|
||||
starter.as_ref().as_ref(),
|
||||
team_choosers.as_ref(),
|
||||
).await;
|
||||
}
|
||||
|
||||
@@ -258,11 +269,37 @@ impl QueueHandler {
|
||||
key,
|
||||
q_entry,
|
||||
user,
|
||||
&self.team_choosers
|
||||
).await
|
||||
}
|
||||
|
||||
fn team_selector(choosers: &crate::team_selection::InitedTeamChoosers, mode: oj_rc_core::data::game_mode::GameMode) -> &'_ oj_rc_core::persist::user::StandardTeamChooser {
|
||||
match mode {
|
||||
oj_rc_core::data::game_mode::GameMode::BattleArena => &choosers.battle_arena,
|
||||
oj_rc_core::data::game_mode::GameMode::SuddenDeath => &choosers.elimination,
|
||||
oj_rc_core::data::game_mode::GameMode::TeamDeathmatch => &choosers.team_deathmatch,
|
||||
oj_rc_core::data::game_mode::GameMode::Pit => &choosers.pit,
|
||||
x => {
|
||||
log::warn!("No team selector available for multiplayer mode {:?}; using elimination", x);
|
||||
&choosers.elimination
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn enter_match_static(hostname: String, hostport: u16, network_conf: crate::data::network::NetworkConfigData, factory: std::sync::Arc<oj_rc_core::factory::Factory>, cpu_counter: std::sync::Arc<oj_rc_core::cubes::CpuListParser>, weapon_guesser: std::sync::Arc<oj_rc_core::cubes::WeaponListParser>, users_per_game: usize, key: QueueKey, mut q_entry: Queue, user: &(dyn oj_rc_core::persist::user::LobbyUser + Send + Sync)) {
|
||||
async fn enter_match_static(
|
||||
hostname: String,
|
||||
hostport: u16,
|
||||
network_conf: crate::data::network::NetworkConfigData,
|
||||
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||
cpu_counter: std::sync::Arc<oj_rc_core::cubes::CpuListParser>,
|
||||
weapon_guesser: std::sync::Arc<oj_rc_core::cubes::WeaponListParser>,
|
||||
users_per_game: usize,
|
||||
key: QueueKey,
|
||||
mut q_entry: Queue,
|
||||
user: &(dyn oj_rc_core::persist::user::LobbyUser + Send + Sync),
|
||||
team_choosers: &crate::team_selection::InitedTeamChoosers,
|
||||
) {
|
||||
let guid_str = key.unique_guid();
|
||||
let game_desc = oj_rc_core::persist::user::GameDescriptor {
|
||||
guid: guid_str.clone(),
|
||||
@@ -275,11 +312,7 @@ impl QueueHandler {
|
||||
is_complete: false,
|
||||
overrides: None,
|
||||
};
|
||||
let team_picker = user.team_chooser(&game_desc).await;
|
||||
/*let team_picker = match key.mode {
|
||||
oj_rc_core::data::game_mode::GameMode::Pit => |i| i as i32, // each player is on a different team
|
||||
_ => |i| (i % 2) as i32, // alternate teams
|
||||
};*/
|
||||
let team_picker = Self::team_selector(team_choosers, game_desc.mode);
|
||||
let mut player_descs = Vec::with_capacity(q_entry.users.len());
|
||||
for (i, player) in q_entry.users.iter_mut().enumerate() {
|
||||
let mut lobby_desc = oj_rc_core::persist::user::PlayerLobbyDescriptor {
|
||||
@@ -297,7 +330,7 @@ impl QueueHandler {
|
||||
|
||||
let missing = users_per_game.saturating_sub(q_entry.users.len());
|
||||
|
||||
match user.start_game(game_desc, player_descs, factory.as_ref(), &cpu_counter, &weapon_guesser, &team_picker, missing).await {
|
||||
match user.start_game(game_desc, player_descs, factory.as_ref(), &cpu_counter, &weapon_guesser, team_picker, missing).await {
|
||||
Ok(fakes) => {
|
||||
let player_datas = q_entry.users.iter().map(|x| x.player.clone())
|
||||
.chain(fakes.players.into_iter().map(|(desc, _emu)| desc),)
|
||||
|
||||
@@ -6,6 +6,7 @@ pub use lobby::QueueHandler;
|
||||
mod data;
|
||||
mod operations;
|
||||
mod events;
|
||||
mod team_selection;
|
||||
|
||||
use oj_polariton_auth::Handshake;
|
||||
use tokio::net;
|
||||
@@ -35,7 +36,12 @@ async fn main() -> std::io::Result<()> {
|
||||
let users = std::sync::Arc::new(oj_rc_core::persist::user::UserImpl::load(&args.data, &config).await.expect("Bad user data"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory(&config, &|| users.factory_impl()).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = oj_rc_core::cubes::CubeParsers::new(&config);
|
||||
let queue = std::sync::Arc::new(QueueHandler::new(&config, &args.redirect, factory.clone(), parsers.cpu_counter(), parsers.weapon_order()));
|
||||
let team_selector_plugins_path = std::path::PathBuf::from(&args.data).join("plugins/team_select");
|
||||
let team_choosers = crate::team_selection::choosers_from_conf(
|
||||
&<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::team_choosers(&config),
|
||||
team_selector_plugins_path,
|
||||
);
|
||||
let queue = std::sync::Arc::new(QueueHandler::new(&config, &args.redirect, factory.clone(), parsers.cpu_counter(), parsers.weapon_order(), team_choosers));
|
||||
|
||||
let init_ctx = InitConfig {
|
||||
config,
|
||||
|
||||
48
rc_lobby_room/src/team_selection.rs
Normal file
48
rc_lobby_room/src/team_selection.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
pub struct InitedTeamChoosers {
|
||||
pub battle_arena: oj_rc_core::persist::user::StandardTeamChooser,
|
||||
pub elimination: oj_rc_core::persist::user::StandardTeamChooser,
|
||||
pub pit: oj_rc_core::persist::user::StandardTeamChooser,
|
||||
pub team_deathmatch: oj_rc_core::persist::user::StandardTeamChooser,
|
||||
}
|
||||
|
||||
pub fn choosers_from_conf(conf: &oj_rc_core::persist::config::TeamChoosers, plugins_path: impl AsRef<std::path::Path>) -> InitedTeamChoosers {
|
||||
InitedTeamChoosers {
|
||||
battle_arena: chooser_from_conf(&conf.battle_arena, &plugins_path),
|
||||
elimination: chooser_from_conf(&conf.elimination, &plugins_path),
|
||||
pit: chooser_from_conf(&conf.pit, &plugins_path),
|
||||
team_deathmatch: chooser_from_conf(&conf.team_deathmatch, &plugins_path),
|
||||
}
|
||||
}
|
||||
|
||||
fn chooser_from_conf(conf: &oj_rc_core::persist::TeamChooser, plugins_path: impl AsRef<std::path::Path>) -> oj_rc_core::persist::user::StandardTeamChooser {
|
||||
match conf {
|
||||
oj_rc_core::persist::TeamChooser::Alternating => oj_rc_core::persist::user::StandardTeamChooser::alternating(),
|
||||
oj_rc_core::persist::TeamChooser::AllOnOne { team } => oj_rc_core::persist::user::StandardTeamChooser::AllOn(*team),
|
||||
oj_rc_core::persist::TeamChooser::OneOnAll => oj_rc_core::persist::user::StandardTeamChooser::OnePer,
|
||||
oj_rc_core::persist::TeamChooser::Custom { path } => {
|
||||
let full_path = plugins_path.as_ref().join(path);
|
||||
log::warn!("Custom team selector plugin {} is experimental and insecure", full_path.display());
|
||||
let result = oj_rc_plugins::team_selection::TeamSelectorCPlugin::new(&full_path);
|
||||
match result {
|
||||
Ok(c_plugin) => oj_rc_core::persist::user::StandardTeamChooser::Custom(Box::new(TeamSelectionPluginWrapper(c_plugin)) as _),
|
||||
Err(e) => {
|
||||
log::error!("Failed to load custom team selector plugin {}: {} (crashing!)", full_path.display(), e);
|
||||
panic!("Failed to load custom team selector plugin {}: {}", full_path.display(), e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TeamSelectionPluginWrapper<T: oj_rc_plugins::team_selection::TeamSelector>(T);
|
||||
|
||||
impl <T: oj_rc_plugins::team_selection::TeamSelector> oj_rc_core::persist::user::TeamChooser for TeamSelectionPluginWrapper<T> {
|
||||
fn choose_team(&self, game: &str, index: usize, player: &oj_rc_core::persist::user::PlayerLobbyDescriptor) -> i32 {
|
||||
self.0.select_team(
|
||||
game,
|
||||
index,
|
||||
if player.user_id >= 0 { Some(player.user_id) } else { None },
|
||||
player.group.clone(),
|
||||
) as i32
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user