mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Allow fake players to have their team chosen automatically at game start
This commit is contained in:
@@ -186,7 +186,7 @@ impl super::config::SelfValidator for GameEvents {
|
|||||||
is_ok = false;
|
is_ok = false;
|
||||||
}
|
}
|
||||||
if matches!(self.multiplayer.mode, GameType::Pit) {
|
if matches!(self.multiplayer.mode, GameType::Pit) {
|
||||||
if ctx.multiplayer.fakes.iter().any(|f| (f.team as usize) < ctx.multiplayer.players_per_game)
|
if ctx.multiplayer.fakes.iter().any(|f| f.team.is_some_and(|t| (t as usize) < ctx.multiplayer.players_per_game))
|
||||||
|| ctx.multiplayer.fakes.iter().enumerate()
|
|| ctx.multiplayer.fakes.iter().enumerate()
|
||||||
.any(|(i, f)| ctx.multiplayer.fakes.iter().enumerate()
|
.any(|(i, f)| ctx.multiplayer.fakes.iter().enumerate()
|
||||||
.any(|(i2, f2)| i != i2 && f.team == f2.team)) {
|
.any(|(i2, f2)| i != i2 && f.team == f2.team)) {
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ pub struct LinksConfig {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FakePlayer {
|
pub struct FakePlayer {
|
||||||
pub team: u8,
|
pub team: Option<u8>,
|
||||||
pub vehicle: VehicleInfo,
|
pub vehicle: VehicleInfo,
|
||||||
pub implementation: ClientEmulator,
|
pub implementation: ClientEmulator,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,19 +34,10 @@ impl super::config::SelfValidator for MultiplayerConfig {
|
|||||||
});
|
});
|
||||||
is_ok = false;
|
is_ok = false;
|
||||||
} else if self.players_per_game == 1 {
|
} else if self.players_per_game == 1 {
|
||||||
if self.fakes.iter().any(|fake| fake.team != 0 && matches!(fake.implementation, ClientEmulation::ClientAI)) {
|
info.warn(super::config::ValidationMessage {
|
||||||
info.error(crate::persist::config::ValidationMessage {
|
path: vec!["players_per_game".to_owned()],
|
||||||
path: vec!["players_per_game".to_owned()],
|
message: "Game match may be lonely with only one player".to_owned(),
|
||||||
message: "Game match cannot have enemy ClientAI fakes when there are no real enemies".to_owned(),
|
});
|
||||||
});
|
|
||||||
is_ok = false;
|
|
||||||
} else {
|
|
||||||
info.warn(super::config::ValidationMessage {
|
|
||||||
path: vec!["players_per_game".to_owned()],
|
|
||||||
message: "Game match may be lonely with only one player".to_owned(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// TODO campaigns
|
// TODO campaigns
|
||||||
// TODO vehicles
|
// TODO vehicles
|
||||||
@@ -97,7 +88,7 @@ pub(super) fn default_net_conf() -> NetworkConf {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct FakePlayerConf {
|
pub struct FakePlayerConf {
|
||||||
pub team: u8,
|
pub team: Option<u8>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub vehicle: super::garage::PrefabVehicle,
|
pub vehicle: super::garage::PrefabVehicle,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@@ -105,10 +96,10 @@ pub struct FakePlayerConf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
||||||
Vec::default()
|
//Vec::default()
|
||||||
/*vec![
|
vec![
|
||||||
FakePlayerConf {
|
/*FakePlayerConf {
|
||||||
team: 1,
|
team: Some(1),
|
||||||
vehicle: super::garage::PrefabVehicle {
|
vehicle: super::garage::PrefabVehicle {
|
||||||
name: Some("fake0".to_owned()),
|
name: Some("fake0".to_owned()),
|
||||||
username: "Server0".to_owned(),
|
username: "Server0".to_owned(),
|
||||||
@@ -118,9 +109,9 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
implementation: ClientEmulation::Experimental,
|
implementation: ClientEmulation::Experimental,
|
||||||
},
|
},*/
|
||||||
FakePlayerConf {
|
FakePlayerConf {
|
||||||
team: 1,
|
team: None,
|
||||||
vehicle: super::garage::PrefabVehicle {
|
vehicle: super::garage::PrefabVehicle {
|
||||||
name: Some("fake1".to_owned()),
|
name: Some("fake1".to_owned()),
|
||||||
username: "Server1".to_owned(),
|
username: "Server1".to_owned(),
|
||||||
@@ -132,7 +123,7 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
|||||||
implementation: ClientEmulation::ClientAI,
|
implementation: ClientEmulation::ClientAI,
|
||||||
},
|
},
|
||||||
FakePlayerConf {
|
FakePlayerConf {
|
||||||
team: 2,
|
team: None,
|
||||||
vehicle: super::garage::PrefabVehicle {
|
vehicle: super::garage::PrefabVehicle {
|
||||||
name: Some("fake2".to_owned()),
|
name: Some("fake2".to_owned()),
|
||||||
username: "Server2".to_owned(),
|
username: "Server2".to_owned(),
|
||||||
@@ -143,7 +134,7 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
|||||||
},
|
},
|
||||||
implementation: ClientEmulation::ClientAI,
|
implementation: ClientEmulation::ClientAI,
|
||||||
},
|
},
|
||||||
]*/
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
use super::account_json::UserData;
|
use super::account_json::UserData;
|
||||||
|
|
||||||
|
pub enum TeamChooser {
|
||||||
|
/// Alternating between team 0 and team 1
|
||||||
|
Alternating,
|
||||||
|
/// All players will be put on the specified team
|
||||||
|
AllOn(u8),
|
||||||
|
/// Each player will be put on their own team (like in Pit mode)
|
||||||
|
OnePer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TeamChooser {
|
||||||
|
pub fn team(&self, index: usize) -> i32 {
|
||||||
|
match self {
|
||||||
|
Self::Alternating => (index % 2) as i32,
|
||||||
|
Self::AllOn(team) => *team as i32,
|
||||||
|
Self::OnePer => index as i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fake_impl_to_db(client_emu: &crate::persist::config::ClientEmulator) -> oj_rc_database::schema::multiplayer_game_player::ClientType {
|
fn fake_impl_to_db(client_emu: &crate::persist::config::ClientEmulator) -> oj_rc_database::schema::multiplayer_game_player::ClientType {
|
||||||
match client_emu {
|
match client_emu {
|
||||||
crate::persist::config::ClientEmulator::Experiment => oj_rc_database::schema::multiplayer_game_player::ClientType::ServerExperimental,
|
crate::persist::config::ClientEmulator::Experiment => oj_rc_database::schema::multiplayer_game_player::ClientType::ServerExperimental,
|
||||||
@@ -24,7 +43,22 @@ impl super::LobbyUser for UserData {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_game(&self, game: super::GameDescriptor, players: Vec<super::PlayerLobbyDescriptor>, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser) -> Result<super::FakePlayers, polariton_server::operations::SimpleOpError> {
|
async fn team_chooser(&self, game: &super::GameDescriptor) -> TeamChooser {
|
||||||
|
match game.mode {
|
||||||
|
crate::data::game_mode::GameMode::Pit => TeamChooser::OnePer,
|
||||||
|
_ => TeamChooser::Alternating,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_game(
|
||||||
|
&self,
|
||||||
|
game: super::GameDescriptor,
|
||||||
|
players: Vec<super::PlayerLobbyDescriptor>,
|
||||||
|
factory: &dyn oj_rc_factory::VehicleFactoryAdapter,
|
||||||
|
cpu_counter: &crate::cubes::CpuListParser,
|
||||||
|
weapon_lister: &crate::cubes::WeaponListParser,
|
||||||
|
chooser: &TeamChooser,
|
||||||
|
) -> Result<super::FakePlayers, polariton_server::operations::SimpleOpError> {
|
||||||
let now = chrono::Utc::now().timestamp();
|
let now = chrono::Utc::now().timestamp();
|
||||||
let guid = crate::persist::user::str_to_i64(&game.guid)
|
let guid = crate::persist::user::str_to_i64(&game.guid)
|
||||||
.ok_or_else(|| polariton_server::operations::SimpleOpError::with_message(
|
.ok_or_else(|| polariton_server::operations::SimpleOpError::with_message(
|
||||||
@@ -39,7 +73,7 @@ impl super::LobbyUser for UserData {
|
|||||||
oj_rc_database::schema::multiplayer_game::GameType::Standard
|
oj_rc_database::schema::multiplayer_game::GameType::Standard
|
||||||
};
|
};
|
||||||
|
|
||||||
let fake_players = self.generate_fake_players_data(guid, factory, cpu_counter, weapon_lister).await?;
|
let fake_players = self.generate_fake_players_data(guid, &players, factory, cpu_counter, weapon_lister, chooser).await?;
|
||||||
|
|
||||||
let game_dbo = oj_rc_database::schema::multiplayer_game::ActiveModel {
|
let game_dbo = oj_rc_database::schema::multiplayer_game::ActiveModel {
|
||||||
id: oj_rc_database::sea_orm::ActiveValue::NotSet,
|
id: oj_rc_database::sea_orm::ActiveValue::NotSet,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub use intercom::generate_token as generate_intercom_token;
|
|||||||
|
|
||||||
mod multiplayer;
|
mod multiplayer;
|
||||||
mod lobby;
|
mod lobby;
|
||||||
|
pub use lobby::TeamChooser;
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
||||||
|
|||||||
@@ -9,8 +9,17 @@ fn db_to_impl(client_emu: &oj_rc_database::schema::multiplayer_game_player::Clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UserData {
|
impl UserData {
|
||||||
pub(super) async fn generate_fake_players_data(&self, _guid: i64, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser) -> Result<Vec<(crate::data::player_data::PlayerData, crate::persist::config::ClientEmulator)>, polariton_server::operations::SimpleOpError> {
|
pub(super) async fn generate_fake_players_data(
|
||||||
|
&self,
|
||||||
|
_guid: i64,
|
||||||
|
real_players: &Vec<super::PlayerLobbyDescriptor>,
|
||||||
|
factory: &dyn oj_rc_factory::VehicleFactoryAdapter,
|
||||||
|
cpu_counter: &crate::cubes::CpuListParser,
|
||||||
|
weapon_lister: &crate::cubes::WeaponListParser,
|
||||||
|
chooser: &super::TeamChooser,
|
||||||
|
) -> Result<Vec<(crate::data::player_data::PlayerData, crate::persist::config::ClientEmulator)>, polariton_server::operations::SimpleOpError> {
|
||||||
let mut fakes = Vec::with_capacity(self.fake_players.len());
|
let mut fakes = Vec::with_capacity(self.fake_players.len());
|
||||||
|
let mut fake_i = real_players.len();
|
||||||
for fake in self.fake_players.iter() {
|
for fake in self.fake_players.iter() {
|
||||||
let vehicle = self.resolve_vehicle(&fake.vehicle, factory, weapon_lister, cpu_counter).await?;
|
let vehicle = self.resolve_vehicle(&fake.vehicle, factory, weapon_lister, cpu_counter).await?;
|
||||||
let out = (
|
let out = (
|
||||||
@@ -22,7 +31,12 @@ impl UserData {
|
|||||||
robot_name: vehicle.robot_name,
|
robot_name: vehicle.robot_name,
|
||||||
robot_map: vehicle.robot_map,
|
robot_map: vehicle.robot_map,
|
||||||
group: None,
|
group: None,
|
||||||
team: fake.team as _,
|
team: fake.team.map(|t| t as i32)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let assigned_team = chooser.team(fake_i);
|
||||||
|
fake_i += 1;
|
||||||
|
assigned_team
|
||||||
|
}),
|
||||||
has_premium: true,
|
has_premium: true,
|
||||||
robot_uuid: vehicle.robot_uuid,
|
robot_uuid: vehicle.robot_uuid,
|
||||||
cpu: vehicle.cpu,
|
cpu: vehicle.cpu,
|
||||||
|
|||||||
@@ -242,7 +242,8 @@ impl SanctionType {
|
|||||||
pub trait LobbyUser {
|
pub trait LobbyUser {
|
||||||
fn user_id(&self) -> i32;
|
fn user_id(&self) -> i32;
|
||||||
async fn player_data(&self, cpu_counter: &crate::cubes::CpuListParser) -> Result<crate::data::player_data::PlayerData, polariton_server::operations::SimpleOpError>;
|
async fn player_data(&self, cpu_counter: &crate::cubes::CpuListParser) -> Result<crate::data::player_data::PlayerData, polariton_server::operations::SimpleOpError>;
|
||||||
async fn start_game(&self, game: GameDescriptor, players: Vec<PlayerLobbyDescriptor>, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser) -> Result<FakePlayers, polariton_server::operations::SimpleOpError>;
|
async fn team_chooser(&self, game: &GameDescriptor) -> super::TeamChooser;
|
||||||
|
async fn start_game(&self, game: GameDescriptor, players: Vec<PlayerLobbyDescriptor>, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser, team_chooser: &super::TeamChooser) -> Result<FakePlayers, polariton_server::operations::SimpleOpError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FakePlayers {
|
pub struct FakePlayers {
|
||||||
|
|||||||
@@ -68,20 +68,6 @@ impl QueueHandler {
|
|||||||
chrono::Utc::now().timestamp_micros().hash(&mut hasher);
|
chrono::Utc::now().timestamp_micros().hash(&mut hasher);
|
||||||
let guid = oj_rc_core::persist::user::uuid_sanitize(hasher.finish() as i64);
|
let guid = oj_rc_core::persist::user::uuid_sanitize(hasher.finish() as i64);
|
||||||
let guid_str = oj_rc_core::persist::user::i64_as_uuid_str(guid);
|
let guid_str = oj_rc_core::persist::user::i64_as_uuid_str(guid);
|
||||||
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
|
|
||||||
};
|
|
||||||
for (i, player) in players.iter_mut().enumerate() {
|
|
||||||
player.player.team = team_picker(i);
|
|
||||||
}
|
|
||||||
let player_descs = players.iter().map(|x| oj_rc_core::persist::user::PlayerLobbyDescriptor {
|
|
||||||
user_id: x.user_id,
|
|
||||||
team: x.player.team,
|
|
||||||
group: None, // TODO support platoons
|
|
||||||
public_id: x.player.name.clone(),
|
|
||||||
display_name: x.player.display_name.clone(),
|
|
||||||
}).collect();
|
|
||||||
let game_desc = oj_rc_core::persist::user::GameDescriptor {
|
let game_desc = oj_rc_core::persist::user::GameDescriptor {
|
||||||
guid: guid_str.clone(),
|
guid: guid_str.clone(),
|
||||||
map: key.map.clone(),
|
map: key.map.clone(),
|
||||||
@@ -92,7 +78,23 @@ impl QueueHandler {
|
|||||||
is_custom: false,
|
is_custom: false,
|
||||||
is_complete: false,
|
is_complete: false,
|
||||||
};
|
};
|
||||||
match user.start_game(game_desc, player_descs, self.factory.as_ref(), &self.cpu_counter, &self.weapon_guesser).await {
|
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
|
||||||
|
};*/
|
||||||
|
for (i, player) in players.iter_mut().enumerate() {
|
||||||
|
player.player.team = team_picker.team(i);
|
||||||
|
}
|
||||||
|
let player_descs = players.iter().map(|x| oj_rc_core::persist::user::PlayerLobbyDescriptor {
|
||||||
|
user_id: x.user_id,
|
||||||
|
team: x.player.team,
|
||||||
|
group: None, // TODO support platoons
|
||||||
|
public_id: x.player.name.clone(),
|
||||||
|
display_name: x.player.display_name.clone(),
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
match user.start_game(game_desc, player_descs, self.factory.as_ref(), &self.cpu_counter, &self.weapon_guesser, &team_picker).await {
|
||||||
Ok(fakes) => {
|
Ok(fakes) => {
|
||||||
let player_datas = players.iter().map(|x| x.player.clone())
|
let player_datas = players.iter().map(|x| x.player.clone())
|
||||||
.chain(fakes.players.into_iter().map(|(desc, _emu)| desc))
|
.chain(fakes.players.into_iter().map(|(desc, _emu)| desc))
|
||||||
|
|||||||
Reference in New Issue
Block a user