mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add basic client AI support
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use polariton::operation::Typed;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlayerData {
|
||||
pub name: String,
|
||||
pub display_name: String,
|
||||
|
||||
@@ -453,9 +453,8 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
||||
|
||||
fn fake_players(&self) -> Vec<super::FakePlayer> {
|
||||
self.battle.multiplayer.fakes.iter().map(|player| super::FakePlayer {
|
||||
public_id: player.public_id.clone(),
|
||||
display_name: player.display_name.clone(),
|
||||
team: player.team,
|
||||
vehicle: player.vehicle.into_conf(),
|
||||
implementation: player.implementation.clone().to_config(),
|
||||
}).collect()
|
||||
}
|
||||
|
||||
@@ -376,15 +376,15 @@ pub struct LinksConfig {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FakePlayer {
|
||||
pub public_id: String,
|
||||
pub display_name: String,
|
||||
pub team: u8,
|
||||
pub vehicle: VehicleInfo,
|
||||
pub implementation: ClientEmulator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ClientEmulator {
|
||||
Experiment,
|
||||
ClientAI,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -58,10 +58,10 @@ pub(super) fn default_net_conf() -> NetworkConf {
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct FakePlayerConf {
|
||||
pub public_id: String,
|
||||
pub display_name: String,
|
||||
pub team: u8,
|
||||
#[serde(flatten)]
|
||||
pub vehicle: super::garage::PrefabVehicle,
|
||||
#[serde(flatten)]
|
||||
pub implementation: ClientEmulation,
|
||||
}
|
||||
|
||||
@@ -69,11 +69,41 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
||||
//Vec::default()
|
||||
vec![
|
||||
FakePlayerConf {
|
||||
public_id: "ServerExperiment01".to_owned(),
|
||||
display_name: "Server".to_owned(),
|
||||
team: 1,
|
||||
vehicle: super::garage::PrefabVehicle {
|
||||
name: Some("fake0".to_owned()),
|
||||
username: "Server0".to_owned(),
|
||||
id: super::garage::PrefabId::Raw {
|
||||
cube_data: Vec::from(crate::persist::VALID_ROBOT),
|
||||
colour_data: Vec::from(crate::persist::VALID_COLOUR),
|
||||
},
|
||||
},
|
||||
implementation: ClientEmulation::Experimental,
|
||||
}
|
||||
},
|
||||
FakePlayerConf {
|
||||
team: 0,
|
||||
vehicle: super::garage::PrefabVehicle {
|
||||
name: Some("fake1".to_owned()),
|
||||
username: "Server1".to_owned(),
|
||||
id: super::garage::PrefabId::Raw {
|
||||
cube_data: Vec::from(crate::persist::VALID_ROBOT),
|
||||
colour_data: Vec::from(crate::persist::VALID_COLOUR),
|
||||
},
|
||||
},
|
||||
implementation: ClientEmulation::ClientAI,
|
||||
},
|
||||
FakePlayerConf {
|
||||
team: 1,
|
||||
vehicle: super::garage::PrefabVehicle {
|
||||
name: Some("fake2".to_owned()),
|
||||
username: "Server2".to_owned(),
|
||||
id: super::garage::PrefabId::Raw {
|
||||
cube_data: Vec::from(crate::persist::VALID_ROBOT),
|
||||
colour_data: Vec::from(crate::persist::VALID_COLOUR),
|
||||
},
|
||||
},
|
||||
implementation: ClientEmulation::ClientAI,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -81,12 +111,14 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
||||
#[serde(tag = "impl")]
|
||||
pub enum ClientEmulation {
|
||||
Experimental,
|
||||
ClientAI,
|
||||
}
|
||||
|
||||
impl ClientEmulation {
|
||||
pub(super) fn to_config(self) -> super::config::ClientEmulator {
|
||||
match self {
|
||||
Self::Experimental => super::config::ClientEmulator::Experiment,
|
||||
Self::ClientAI => super::config::ClientEmulator::ClientAI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use argon2::PasswordVerifier;
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::persist::config::ConfigProvider;
|
||||
|
||||
@@ -418,11 +419,22 @@ impl UserData {
|
||||
}
|
||||
|
||||
pub(super) async fn resolve_vehicle(&self, vehicle: &crate::persist::config::VehicleInfo, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser, cpu_counter: &crate::cubes::CpuListParser) -> Result<super::ResolvedVehicle, polariton_server::operations::SimpleOpError> {
|
||||
let sha_bytes = sha2::Sha256::digest(vehicle.username.as_bytes());
|
||||
let u32_bytes = [
|
||||
sha_bytes[0],
|
||||
sha_bytes[1],
|
||||
sha_bytes[2],
|
||||
sha_bytes[3],
|
||||
];
|
||||
let standard_uuid_uniqueness = (u32::from_be_bytes(u32_bytes) as i64) << 16; // middle 32 bits
|
||||
match &vehicle.id {
|
||||
crate::persist::config::VehicleDescriptor::Factory { factory: factory_id } => {
|
||||
match factory.vehicle(*factory_id).await {
|
||||
Ok(Some(factory_vehicle)) => {
|
||||
let uuid_i64 = crate::persist::user::uuid_sanitize(crate::persist::user::i64_join((1 << 30, *factory_id)));
|
||||
let uuid_i64 = crate::persist::user::uuid_sanitize(
|
||||
standard_uuid_uniqueness
|
||||
^ crate::persist::user::i64_join((1 << 30, *factory_id))
|
||||
);
|
||||
let uuid_str = crate::persist::user::i64_as_uuid_str(uuid_i64);
|
||||
let weapons_guess = weapon_order.guess_weapons(&mut std::io::Cursor::new(&factory_vehicle.0.cube_data));
|
||||
let weapons_guess = vec![weapons_guess[0], 0, 0];
|
||||
@@ -470,7 +482,10 @@ impl UserData {
|
||||
} else {
|
||||
db_vehicle.total_robot_cpu
|
||||
};
|
||||
let uuid_i64 = crate::persist::user::uuid_sanitize(crate::persist::user::i64_join((1 << 31, *garage as u32)));
|
||||
let uuid_i64 = crate::persist::user::uuid_sanitize(
|
||||
standard_uuid_uniqueness
|
||||
^ crate::persist::user::i64_join((1 << 31, *garage as u32))
|
||||
);
|
||||
let uuid_str = crate::persist::user::i64_as_uuid_str(uuid_i64);
|
||||
Ok(super::ResolvedVehicle {
|
||||
mastery: 1,
|
||||
@@ -506,7 +521,6 @@ impl UserData {
|
||||
cube_data,
|
||||
colour_data,
|
||||
} => {
|
||||
use sha2::Digest;
|
||||
let sha_bytes = sha2::Sha256::digest(cube_data);
|
||||
let u32_bytes = [
|
||||
sha_bytes[0],
|
||||
@@ -514,7 +528,10 @@ impl UserData {
|
||||
sha_bytes[2],
|
||||
sha_bytes[3],
|
||||
];
|
||||
let uuid_i64 = crate::persist::user::uuid_sanitize(crate::persist::user::i64_join((1 << 29, u32::from_le_bytes(u32_bytes))));
|
||||
let uuid_i64 = crate::persist::user::uuid_sanitize(
|
||||
standard_uuid_uniqueness
|
||||
^ crate::persist::user::i64_join((1 << 29, u32::from_le_bytes(u32_bytes)))
|
||||
);
|
||||
let uuid_str = crate::persist::user::i64_as_uuid_str(uuid_i64);
|
||||
let weapons_guess = weapon_order.guess_weapons(&mut std::io::Cursor::new(&cube_data));
|
||||
let weapons_guess = vec![
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
use super::account_json::UserData;
|
||||
|
||||
fn fake_impl_to_db(client_emu: &crate::persist::config::ClientEmulator) -> oj_rc_database::schema::multiplayer_game_player::ClientType {
|
||||
match client_emu {
|
||||
crate::persist::config::ClientEmulator::Experiment => oj_rc_database::schema::multiplayer_game_player::ClientType::ServerExperimental,
|
||||
crate::persist::config::ClientEmulator::ClientAI => oj_rc_database::schema::multiplayer_game_player::ClientType::ClientAI,
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl super::LobbyUser for UserData {
|
||||
fn user_id(&self) -> i32 {
|
||||
@@ -17,7 +24,7 @@ impl super::LobbyUser for UserData {
|
||||
})
|
||||
}
|
||||
|
||||
async fn start_game(&self, game: super::GameDescriptor, players: Vec<super::PlayerLobbyDescriptor>, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser) -> Result<super::FakePlayers, polariton_server::operations::SimpleOpError> {
|
||||
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> {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
let guid = crate::persist::user::str_to_i64(&game.guid)
|
||||
.ok_or_else(|| polariton_server::operations::SimpleOpError::with_message(
|
||||
@@ -32,7 +39,7 @@ impl super::LobbyUser for UserData {
|
||||
oj_rc_database::schema::multiplayer_game::GameType::Standard
|
||||
};
|
||||
|
||||
let fake_players = self.generate_fake_players_data(guid, cpu_counter, weapon_lister).await;
|
||||
let fake_players = self.generate_fake_players_data(guid, factory, cpu_counter, weapon_lister).await?;
|
||||
|
||||
let game_dbo = oj_rc_database::schema::multiplayer_game::ActiveModel {
|
||||
id: oj_rc_database::sea_orm::ActiveValue::NotSet,
|
||||
@@ -69,14 +76,15 @@ impl super::LobbyUser for UserData {
|
||||
is_claimed: oj_rc_database::sea_orm::ActiveValue::Set(false),
|
||||
public_id: oj_rc_database::sea_orm::ActiveValue::Set(player.public_id),
|
||||
display_name: oj_rc_database::sea_orm::ActiveValue::Set(player.display_name),
|
||||
variant: oj_rc_database::sea_orm::ActiveValue::Set(oj_rc_database::schema::multiplayer_game_player::ClientType::Client),
|
||||
}
|
||||
})
|
||||
.chain(fake_players.iter()
|
||||
.enumerate()
|
||||
.map(|(i, fake)| {
|
||||
.map(|(i, (fake, variant))| {
|
||||
oj_rc_database::schema::multiplayer_game_player::ActiveModel {
|
||||
id: oj_rc_database::sea_orm::ActiveValue::NotSet,
|
||||
user_id: oj_rc_database::sea_orm::ActiveValue::Set(None),
|
||||
user_id: oj_rc_database::sea_orm::ActiveValue::Set(None), // if ClientAI, they will be assigned to a user during game loading
|
||||
game_id: oj_rc_database::sea_orm::ActiveValue::Set(game_dbo.id),
|
||||
creation_time: oj_rc_database::sea_orm::ActiveValue::Set(now),
|
||||
player_id: oj_rc_database::sea_orm::ActiveValue::Set(((i + players_len) as u8) as _),
|
||||
@@ -85,6 +93,7 @@ impl super::LobbyUser for UserData {
|
||||
is_claimed: oj_rc_database::sea_orm::ActiveValue::Set(true),
|
||||
public_id: oj_rc_database::sea_orm::ActiveValue::Set(fake.name.clone()),
|
||||
display_name: oj_rc_database::sea_orm::ActiveValue::Set(fake.display_name.clone()),
|
||||
variant: oj_rc_database::sea_orm::ActiveValue::Set(fake_impl_to_db(variant)),
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
@@ -1,30 +1,45 @@
|
||||
use super::account_json::UserData;
|
||||
|
||||
fn db_to_impl(client_emu: &oj_rc_database::schema::multiplayer_game_player::ClientType) -> Option<crate::persist::config::ClientEmulator> {
|
||||
match client_emu {
|
||||
oj_rc_database::schema::multiplayer_game_player::ClientType::ServerExperimental => Some(crate::persist::config::ClientEmulator::Experiment),
|
||||
oj_rc_database::schema::multiplayer_game_player::ClientType::ClientAI => Some(crate::persist::config::ClientEmulator::ClientAI),
|
||||
oj_rc_database::schema::multiplayer_game_player::ClientType::Client => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData {
|
||||
pub(super) async fn generate_fake_players_data(&self, _guid: i64, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser) -> Vec<crate::data::player_data::PlayerData> {
|
||||
self.fake_players.iter()
|
||||
.map(|fake| crate::data::player_data::PlayerData {
|
||||
name: fake.public_id.clone(),
|
||||
display_name: fake.display_name.clone(),
|
||||
mastery: 1,
|
||||
tier: 1,
|
||||
robot_name: "fake".to_owned(),
|
||||
robot_map: crate::persist::VALID_ROBOT.into(),
|
||||
group: None,
|
||||
team: fake.team as _,
|
||||
has_premium: true,
|
||||
robot_uuid: "1234_1234".to_owned(),
|
||||
cpu: cpu_counter.calculate_cpu(&mut std::io::Cursor::new(crate::persist::VALID_ROBOT)).total as _,
|
||||
avatar_id: Some(0),
|
||||
weapon_order: weapon_lister.guess_weapons(&mut std::io::Cursor::new(crate::persist::VALID_ROBOT)),
|
||||
colour_map: crate::persist::VALID_COLOUR.into(),
|
||||
is_ai: false,
|
||||
spawn_effect: "Spawn".into(),
|
||||
death_effect: "Explosion".into(),
|
||||
player_rank: 1,
|
||||
weapon_rank: Default::default(),
|
||||
})
|
||||
.collect()
|
||||
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> {
|
||||
let mut fakes = Vec::with_capacity(self.fake_players.len());
|
||||
for fake in self.fake_players.iter() {
|
||||
let vehicle = self.resolve_vehicle(&fake.vehicle, factory, weapon_lister, cpu_counter).await?;
|
||||
let out = (
|
||||
crate::data::player_data::PlayerData {
|
||||
name: fake.vehicle.username.clone(),
|
||||
display_name: fake.vehicle.username.clone(),
|
||||
mastery: vehicle.mastery,
|
||||
tier: vehicle.mastery,
|
||||
robot_name: vehicle.robot_name,
|
||||
robot_map: vehicle.robot_map,
|
||||
group: None,
|
||||
team: fake.team as _,
|
||||
has_premium: true,
|
||||
robot_uuid: vehicle.robot_uuid,
|
||||
cpu: vehicle.cpu,
|
||||
avatar_id: Some(0),
|
||||
weapon_order: vehicle.weapon_order,
|
||||
colour_map: vehicle.colour_map,
|
||||
is_ai: fake.implementation == crate::persist::config::ClientEmulator::ClientAI,
|
||||
spawn_effect: vehicle.spawn_effect,
|
||||
death_effect: vehicle.death_effect,
|
||||
player_rank: 1,
|
||||
weapon_rank: vehicle.weapon_rank,
|
||||
},
|
||||
fake.implementation
|
||||
);
|
||||
fakes.push(out);
|
||||
}
|
||||
Ok(fakes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +97,7 @@ impl super::MultiplayerUser for UserData {
|
||||
is_rewards_claimed: player.is_claimed,
|
||||
display_name: player.display_name,
|
||||
public_id: player.public_id,
|
||||
mode: db_to_impl(&player.variant),
|
||||
})
|
||||
.collect())
|
||||
} else {
|
||||
|
||||
@@ -247,11 +247,11 @@ impl SanctionType {
|
||||
pub trait LobbyUser {
|
||||
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 start_game(&self, game: GameDescriptor, players: Vec<PlayerLobbyDescriptor>, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser) -> Result<FakePlayers, 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>;
|
||||
}
|
||||
|
||||
pub struct FakePlayers {
|
||||
pub players: Vec<crate::data::player_data::PlayerData>
|
||||
pub players: Vec<(crate::data::player_data::PlayerData, crate::persist::config::ClientEmulator)>
|
||||
}
|
||||
|
||||
pub struct CurrentGameEvent {
|
||||
@@ -291,6 +291,7 @@ pub struct PlayerDescriptor {
|
||||
pub public_id: String,
|
||||
pub display_name: String,
|
||||
pub is_rewards_claimed: bool,
|
||||
pub mode: Option<crate::persist::config::ClientEmulator>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
Reference in New Issue
Block a user