1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Fix dominating message, fix fake player loading, mess around with reactor crystals

This commit is contained in:
NG (Graham)
2026-01-15 18:49:29 -05:00
parent 16f0761380
commit a48f9dcfe9
13 changed files with 222 additions and 52 deletions

16
Cargo.lock generated
View File

@@ -2424,6 +2424,22 @@ dependencies = [
"zip", "zip",
] ]
[[package]]
name = "oj_factory_api"
version = "1.1.0"
dependencies = [
"actix-web",
"base64",
"clap",
"env_logger",
"git-version",
"libfj",
"log",
"oj_rc_core",
"oj_rc_factory",
"serde_json",
]
[[package]] [[package]]
name = "oj_polariton_auth" name = "oj_polariton_auth"
version = "1.1.0" version = "1.1.0"

View File

@@ -12264,7 +12264,8 @@
"active": true, "active": true,
"protonium": true, "protonium": true,
"visibility": "None", "visibility": "None",
"ignore_in_weapon_list": true "ignore_in_weapon_list": true,
"health": 10000
}, },
"spriteName": "CubeThumb_LightChassis_Cube", "spriteName": "CubeThumb_LightChassis_Cube",
"nameStrKey": "strProtoniumCrystalName", "nameStrKey": "strProtoniumCrystalName",

View File

@@ -42,33 +42,41 @@ impl CubeLocationsParser {
} }
} }
fn locations_sorted_by_distance_from_point(cubes: &[super::parser::Cube], point: (u8, u8, u8), locations_of_id: u32) -> Vec<CubeLocationInfo> {
let target_x = point.0 as f32;
let target_y = point.1 as f32;
let target_z = point.2 as f32;
let mut relevant_cubes: Vec<(f32, CubeLocationInfo)> = cubes.into_iter()
.filter(|x| x.id == locations_of_id)
.map(|cube| {
let distance = (
(cube.x as f32 - target_x).powi(2)
+ (cube.y as f32 - target_y).powi(2)
+ (cube.z as f32 - target_z).powi(2)
).sqrt();
(distance, CubeLocationInfo {
x: cube.x,
y: cube.y,
z: cube.z,
extras: cube.orientation,
})
})
.collect();
relevant_cubes.sort_by_key(|(distance, _)| (distance * 1_000_000.0) as i64);
relevant_cubes.into_iter()
.map(|(_, cube)| cube)
.collect()
}
pub fn locations_of_by_distance_to_first(&self, r: &mut dyn std::io::Read, locations_of_id: u32, distance_to_id: u32) -> Vec<CubeLocationInfo> { pub fn locations_of_by_distance_to_first(&self, r: &mut dyn std::io::Read, locations_of_id: u32, distance_to_id: u32) -> Vec<CubeLocationInfo> {
match super::parser::Cube::parse_list(r) { match super::parser::Cube::parse_list(r) {
Ok(cubes) => { Ok(cubes) => {
if let Some(target) = cubes.iter().find(|x| x.id == distance_to_id) { if let Some(target) = cubes.iter().find(|x| x.id == distance_to_id) {
let target_x = target.x as f32; Self::locations_sorted_by_distance_from_point(
let target_y = target.y as f32; &cubes,
let target_z = target.z as f32; (target.x, target.y, target.z),
let mut relevant_cubes: Vec<(f32, CubeLocationInfo)> = cubes.into_iter() locations_of_id,
.filter(|x| x.id == locations_of_id) )
.map(|cube| {
let distance = (
(cube.x as f32 - target_x).powi(2)
+ (cube.y as f32 - target_y).powi(2)
+ (cube.z as f32 - target_z).powi(2)
).sqrt();
(distance, CubeLocationInfo {
x: cube.x,
y: cube.y,
z: cube.z,
extras: cube.orientation,
})
})
.collect();
relevant_cubes.sort_by_key(|(distance, _)| (distance * 1_000_000.0) as i64);
relevant_cubes.into_iter()
.map(|(_, cube)| cube)
.collect()
} else { } else {
log::warn!("No cube with id {} to calculate distance", distance_to_id); log::warn!("No cube with id {} to calculate distance", distance_to_id);
cubes.into_iter() cubes.into_iter()
@@ -89,4 +97,20 @@ impl CubeLocationsParser {
} }
} }
} }
pub fn locations_of_by_distance_from(&self, r: &mut dyn std::io::Read, locations_of_id: u32, from: (u8, u8, u8)) -> Vec<CubeLocationInfo> {
match super::parser::Cube::parse_list(r) {
Ok(cubes) => {
Self::locations_sorted_by_distance_from_point(
&cubes,
from,
locations_of_id,
)
}
Err(e) => {
log::error!("Failed to parse cube data to find cube locations: {}", e);
Vec::default()
}
}
}
} }

View File

@@ -336,7 +336,7 @@ fn default_game_modes() -> GameModes {
respawn_heal_duration: 10.0, respawn_heal_duration: 10.0,
respawn_full_heal_duration: 0.5, respawn_full_heal_duration: 0.5,
kill_limit: 0, kill_limit: 0,
game_time_m: 2, game_time_m: 20,
}, },
elimination: GameMode { elimination: GameMode {
respawn_heal_duration: 10.0, respawn_heal_duration: 10.0,
@@ -622,6 +622,7 @@ fn default_multiplayer() -> super::MultiplayerConfig {
autostart_after_s: 180, autostart_after_s: 180,
network: super::multiplayer::default_net_conf(), network: super::multiplayer::default_net_conf(),
fakes: super::multiplayer::default_fake_users(), fakes: super::multiplayer::default_fake_users(),
filler: super::multiplayer::default_filler_users(),
battle_arena: super::multiplayer::default_ba_conf(), battle_arena: super::multiplayer::default_ba_conf(),
pit_config: super::multiplayer::default_pit_conf(), pit_config: super::multiplayer::default_pit_conf(),
team_death_match: super::multiplayer::default_tdm_conf(), team_death_match: super::multiplayer::default_tdm_conf(),

View File

@@ -488,6 +488,14 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
}).collect() }).collect()
} }
fn filler_players(&self) -> Vec<super::FakePlayer> {
self.battle.multiplayer.filler.iter().map(|player| super::FakePlayer {
team: player.team,
vehicle: player.vehicle.into_conf(),
implementation: player.implementation.clone().to_config(),
}).collect()
}
fn energy(&self) -> super::EnergyConfig { fn energy(&self) -> super::EnergyConfig {
super::EnergyConfig { super::EnergyConfig {
refill_rate: self.battle.energy.refill_rate_per_s, refill_rate: self.battle.energy.refill_rate_per_s,

View File

@@ -34,6 +34,7 @@ pub trait ConfigProvider<C: Clone> {
fn maps(&self) -> std::collections::HashMap<GameMap, MapConfig>; fn maps(&self) -> std::collections::HashMap<GameMap, MapConfig>;
fn url_links(&self) -> LinksConfig; fn url_links(&self) -> LinksConfig;
fn fake_players(&self) -> Vec<FakePlayer>; fn fake_players(&self) -> Vec<FakePlayer>;
fn filler_players(&self) -> Vec<FakePlayer>;
fn energy(&self) -> EnergyConfig; fn energy(&self) -> EnergyConfig;
fn ba_settings(&self) -> BattleArenaResolver; fn ba_settings(&self) -> BattleArenaResolver;
fn pit_settings(&self) -> PitSettings; fn pit_settings(&self) -> PitSettings;

View File

@@ -9,6 +9,8 @@ pub struct MultiplayerConfig {
pub network: NetworkConf, pub network: NetworkConf,
#[serde(default = "default_fake_users")] #[serde(default = "default_fake_users")]
pub fakes: Vec<FakePlayerConf>, pub fakes: Vec<FakePlayerConf>,
#[serde(default = "default_filler_users")]
pub filler: Vec<FakePlayerConf>,
#[serde(default = "default_ba_conf")] #[serde(default = "default_ba_conf")]
pub battle_arena: BattleArenaConfig, pub battle_arena: BattleArenaConfig,
#[serde(default = "default_pit_conf")] #[serde(default = "default_pit_conf")]
@@ -166,6 +168,10 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
] ]
} }
pub(super) fn default_filler_users() -> Vec<FakePlayerConf> {
default_fake_users()
}
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "impl")] #[serde(tag = "impl")]
pub enum ClientEmulation { pub enum ClientEmulation {
@@ -242,7 +248,7 @@ fn default_ba_base() -> super::garage::PrefabVehicle {
} }
fn default_crystal_health() -> u32 { fn default_crystal_health() -> u32 {
1_000 10_000
} }
fn default_respawn_time() -> u64 { fn default_respawn_time() -> u64 {

View File

@@ -8,6 +8,7 @@ pub struct AccountProvider {
cubes: std::sync::Arc<Vec<u32>>, cubes: std::sync::Arc<Vec<u32>>,
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>, garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
fake_players: std::sync::Arc<Vec<crate::persist::config::FakePlayer>>, fake_players: std::sync::Arc<Vec<crate::persist::config::FakePlayer>>,
filler_players: std::sync::Arc<Vec<crate::persist::config::FakePlayer>>,
auto_signups: bool, auto_signups: bool,
cdn: std::sync::Arc<String>, cdn: std::sync::Arc<String>,
auth: std::sync::Arc<String>, auth: std::sync::Arc<String>,
@@ -30,6 +31,7 @@ impl AccountProvider {
cubes: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::ids(conf)), cubes: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::ids(conf)),
garage_upgrades: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::garage_upgrades(conf)), garage_upgrades: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::garage_upgrades(conf)),
fake_players: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::fake_players(conf)), fake_players: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::fake_players(conf)),
filler_players: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::filler_players(conf)),
auto_signups: server_settings.auto_signup, auto_signups: server_settings.auto_signup,
cdn: std::sync::Arc::new(server_settings.cdn_url), cdn: std::sync::Arc::new(server_settings.cdn_url),
auth: std::sync::Arc::new(server_settings.auth_url), auth: std::sync::Arc::new(server_settings.auth_url),
@@ -113,6 +115,7 @@ impl <C: Clone + Send> super::UserProvider<C> for AccountProvider {
cubes: self.cubes.clone(), cubes: self.cubes.clone(),
garage_upgrades: self.garage_upgrades.clone(), garage_upgrades: self.garage_upgrades.clone(),
fake_players: self.fake_players.clone(), fake_players: self.fake_players.clone(),
filler_players: self.filler_players.clone(),
cdn: self.cdn.clone(), cdn: self.cdn.clone(),
auth: self.auth.clone(), auth: self.auth.clone(),
intercom: self.intercom.clone(), intercom: self.intercom.clone(),
@@ -151,6 +154,7 @@ impl <C: Clone + Send> super::UserProvider<C> for AccountProvider {
cubes: self.cubes.clone(), cubes: self.cubes.clone(),
garage_upgrades: self.garage_upgrades.clone(), garage_upgrades: self.garage_upgrades.clone(),
fake_players: self.fake_players.clone(), fake_players: self.fake_players.clone(),
filler_players: self.filler_players.clone(),
cdn: self.cdn.clone(), cdn: self.cdn.clone(),
auth: self.auth.clone(), auth: self.auth.clone(),
intercom: self.intercom.clone(), intercom: self.intercom.clone(),
@@ -316,6 +320,7 @@ pub(super) struct UserData {
pub(super) cubes: std::sync::Arc<Vec<u32>>, pub(super) cubes: std::sync::Arc<Vec<u32>>,
pub(super) garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>, pub(super) garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
pub(super) fake_players: std::sync::Arc<Vec<crate::persist::config::FakePlayer>>, pub(super) fake_players: std::sync::Arc<Vec<crate::persist::config::FakePlayer>>,
pub(super) filler_players: std::sync::Arc<Vec<crate::persist::config::FakePlayer>>,
pub(super) cdn: std::sync::Arc<String>, pub(super) cdn: std::sync::Arc<String>,
pub(super) auth: std::sync::Arc<String>, pub(super) auth: std::sync::Arc<String>,
pub(super) intercom: std::sync::Arc<String>, pub(super) intercom: std::sync::Arc<String>,

View File

@@ -58,6 +58,7 @@ impl super::LobbyUser for UserData {
cpu_counter: &crate::cubes::CpuListParser, cpu_counter: &crate::cubes::CpuListParser,
weapon_lister: &crate::cubes::WeaponListParser, weapon_lister: &crate::cubes::WeaponListParser,
chooser: &TeamChooser, chooser: &TeamChooser,
missing_players: usize,
) -> Result<super::FakePlayers, polariton_server::operations::SimpleOpError> { ) -> 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)
@@ -73,7 +74,8 @@ 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, &players, factory, cpu_counter, weapon_lister, chooser).await?; let forced_fake_players = self.generate_forced_fake_players_data(guid, &players, factory, cpu_counter, weapon_lister, chooser).await?;
let filler_players = self.generate_filler_players_data(guid, &players, factory, cpu_counter, weapon_lister, chooser, missing_players).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,
@@ -95,6 +97,7 @@ impl super::LobbyUser for UserData {
})?; })?;
let players_len = players.len(); let players_len = players.len();
let forced_fake_players_len = forced_fake_players.len();
let players: Vec<oj_rc_database::schema::multiplayer_game_player::ActiveModel> = players.into_iter() let players: Vec<oj_rc_database::schema::multiplayer_game_player::ActiveModel> = players.into_iter()
.enumerate() .enumerate()
@@ -113,7 +116,7 @@ impl super::LobbyUser for UserData {
variant: oj_rc_database::sea_orm::ActiveValue::Set(oj_rc_database::schema::multiplayer_game_player::ClientType::Client), variant: oj_rc_database::sea_orm::ActiveValue::Set(oj_rc_database::schema::multiplayer_game_player::ClientType::Client),
} }
}) })
.chain(fake_players.iter() .chain(forced_fake_players.iter()
.enumerate() .enumerate()
.map(|(i, (fake, variant))| { .map(|(i, (fake, variant))| {
oj_rc_database::schema::multiplayer_game_player::ActiveModel { oj_rc_database::schema::multiplayer_game_player::ActiveModel {
@@ -131,6 +134,24 @@ impl super::LobbyUser for UserData {
} }
}) })
) )
.chain(filler_players.iter()
.enumerate()
.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), // 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 + forced_fake_players_len) as u8) as _),
team: oj_rc_database::sea_orm::ActiveValue::Set(fake.team),
group: oj_rc_database::sea_orm::ActiveValue::Set(None),
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)),
}
})
)
.collect(); .collect();
self.db.insert_players(players).await.map_err(|e| { self.db.insert_players(players).await.map_err(|e| {
log::error!("Failed to create game players for {} through user_id {}: {}", game.guid, self.account.id, e); log::error!("Failed to create game players for {} through user_id {}: {}", game.guid, self.account.id, e);
@@ -140,6 +161,8 @@ impl super::LobbyUser for UserData {
) )
})?; })?;
Ok(super::FakePlayers { players: fake_players }) Ok(super::FakePlayers {
players: forced_fake_players.into_iter().chain(filler_players).collect(),
})
} }
} }

View File

@@ -17,10 +17,11 @@ impl UserData {
cpu_counter: &crate::cubes::CpuListParser, cpu_counter: &crate::cubes::CpuListParser,
weapon_lister: &crate::cubes::WeaponListParser, weapon_lister: &crate::cubes::WeaponListParser,
chooser: &super::TeamChooser, chooser: &super::TeamChooser,
fake_players: &[crate::persist::config::FakePlayer],
) -> Result<Vec<(crate::data::player_data::PlayerData, crate::persist::config::ClientEmulator)>, polariton_server::operations::SimpleOpError> { ) -> 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(fake_players.len());
let mut fake_i = real_players.len(); let mut fake_i = real_players.len();
for fake in self.fake_players.iter() { for fake in 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 = (
crate::data::player_data::PlayerData { crate::data::player_data::PlayerData {
@@ -55,6 +56,47 @@ impl UserData {
} }
Ok(fakes) Ok(fakes)
} }
pub(super) async fn generate_forced_fake_players_data(
&self,
guid: i64,
real_players: &[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> {
self.generate_fake_players_data(
guid,
real_players,
factory,
cpu_counter,
weapon_lister,
chooser,
&self.fake_players,
).await
}
pub(super) async fn generate_filler_players_data(
&self,
guid: i64,
real_players: &[super::PlayerLobbyDescriptor],
factory: &dyn oj_rc_factory::VehicleFactoryAdapter,
cpu_counter: &crate::cubes::CpuListParser,
weapon_lister: &crate::cubes::WeaponListParser,
chooser: &super::TeamChooser,
count: usize,
) -> Result<Vec<(crate::data::player_data::PlayerData, crate::persist::config::ClientEmulator)>, polariton_server::operations::SimpleOpError> {
self.generate_fake_players_data(
guid,
real_players,
factory,
cpu_counter,
weapon_lister,
chooser,
&self.filler_players[0..count],
).await
}
} }
#[async_trait::async_trait] #[async_trait::async_trait]

View File

@@ -265,7 +265,7 @@ 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 team_chooser(&self, game: &GameDescriptor) -> super::TeamChooser; 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>; 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, missing_players: usize) -> Result<FakePlayers, polariton_server::operations::SimpleOpError>;
} }
pub struct FakePlayers { pub struct FakePlayers {

View File

@@ -217,11 +217,12 @@ impl QueueHandler {
display_name: x.player.display_name.clone(), display_name: x.player.display_name.clone(),
}).collect(); }).collect();
match user.start_game(game_desc, player_descs, factory.as_ref(), &cpu_counter, &weapon_guesser, &team_picker).await { let missing = users_per_game.saturating_sub(players.len());
match user.start_game(game_desc, player_descs, factory.as_ref(), &cpu_counter, &weapon_guesser, &team_picker, missing).await {
Ok(fakes) => { Ok(fakes) => {
let missing = users_per_game.saturating_sub(players.len());
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().take(missing).map(|(desc, _emu)| desc),) .chain(fakes.players.into_iter().map(|(desc, _emu)| desc),)
.collect(); .collect();
let enter_battle_ev = crate::events::battle_enter::BattleEnter { let enter_battle_ev = crate::events::battle_enter::BattleEnter {
host: hostname.clone(), host: hostname.clone(),

View File

@@ -721,7 +721,7 @@ struct BaseTickInfo {
} }
impl BaseTracker { impl BaseTracker {
const DOMINATING_MULT: f32 = 10.0; const DOMINATING_MULT: f32 = 4.0;
fn new<'a>(bases_iter: impl std::iter::Iterator<Item=&'a u8>, crystals: &[oj_rc_core::cubes::CubeLocationInfo], ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData) -> Self { fn new<'a>(bases_iter: impl std::iter::Iterator<Item=&'a u8>, crystals: &[oj_rc_core::cubes::CubeLocationInfo], ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData) -> Self {
let mut bases = std::collections::HashMap::new(); let mut bases = std::collections::HashMap::new();
@@ -735,19 +735,40 @@ impl BaseTracker {
} }
} }
fn apply_partial_base_heal(&self, crystals: &[oj_rc_core::cubes::CubeLocationInfo], crystal_health: u32, base_id: u8, base: &BaseInfo, old_index: usize, new_index: usize) -> rlnl::events::HealedCubes {
//let base = self.bases.get(&base_id).unwrap();
let target_crystals = &crystals[old_index..new_index];
for crystal_i in old_index..new_index {
base.crystals_healths[crystal_i].store(u8::MAX, std::sync::atomic::Ordering::Relaxed);
}
rlnl::events::HealedCubes {
healed_machine: base_id as u16,
type_performing_healing: rlnl::types::TargetType::TeamBase,
target_type: rlnl::types::TargetType::TeamBase,
num_healed_cubes: target_crystals.len() as _,
hit_cubes: target_crystals
.iter()
.map(|loc| rlnl::types::HitCubeInfo {
pos: rlnl::types::Byte3 { x: loc.x, y: loc.y, z: loc.z, },
damage: crystal_health as i32,
})
.collect(),
}
}
async fn tick(&self, tick_info: &PointTickInfo, crystals: &[oj_rc_core::cubes::CubeLocationInfo], generic: &crate::matches::GenericGamemodeEngine<BattleArenaLogic>, capture_points_count: usize, crystal_health: u32, ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData) -> BaseTickInfo { async fn tick(&self, tick_info: &PointTickInfo, crystals: &[oj_rc_core::cubes::CubeLocationInfo], generic: &crate::matches::GenericGamemodeEngine<BattleArenaLogic>, capture_points_count: usize, crystal_health: u32, ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData) -> BaseTickInfo {
let multiplier = if let Some(dominant_team) = tick_info.dominating { let multiplier = if let Some(dominant_team) = tick_info.dominating {
if !self.dominating.swap(true, std::sync::atomic::Ordering::Relaxed) { if !self.dominating.swap(true, std::sync::atomic::Ordering::Relaxed) {
log::info!("Team {} is now dominating game {}", dominant_team, generic.game_guid()); log::info!("Team {} is now dominating game {}", dominant_team, generic.game_guid());
// FIXME this doesn't seem to trigger the announcement client-side
generic.broadcast( generic.broadcast(
rlnl::event_code::NetworkEvent::CapturePointNotification, rlnl::event_code::NetworkEvent::CapturePointNotification,
literustlib::packet::Property::ReliableOrdered, literustlib::packet::Property::ReliableOrdered,
&rlnl::events::ingame::CapturePointNotification { &rlnl::events::ingame::CapturePointNotification {
notification: rlnl::types::CapturePointNotificationType::Dominating, notification: rlnl::types::CapturePointNotificationType::Dominating,
id: dominant_team, id: u8::MAX, // ignored?
defending_team: dominant_team as i8, attacking_team: dominant_team as i8,
attacking_team: (((dominant_team as usize) + 1) % generic.map_config.bases.len()) as i8 defending_team: -1, // ignored?
//defending_team: (((dominant_team as usize) + 1) % generic.map_config.bases.len()) as i8
}, },
true true
).await; ).await;
@@ -795,7 +816,8 @@ impl BaseTracker {
], ],
} }
} else { } else {
let target_crystals = &crystals[old_index..new_index]; self.apply_partial_base_heal(crystals, crystal_health, *base_id, tracked_base, old_index, new_index)
/*let target_crystals = &crystals[old_index..new_index];
for crystal_i in old_index..new_index { for crystal_i in old_index..new_index {
tracked_base.crystals_healths[crystal_i].store(u8::MAX, std::sync::atomic::Ordering::Relaxed); tracked_base.crystals_healths[crystal_i].store(u8::MAX, std::sync::atomic::Ordering::Relaxed);
} }
@@ -811,7 +833,7 @@ impl BaseTracker {
damage: crystal_health as i32, damage: crystal_health as i32,
}) })
.collect(), .collect(),
} }*/
}; };
generic.broadcast( generic.broadcast(
@@ -974,6 +996,7 @@ impl BattleArenaLogic {
pub fn new(config: &oj_rc_core::data::game_mode::GameModeConfig, map: &oj_rc_core::persist::config::MapConfig, parsers: &oj_rc_core::cubes::CubeParsers, players: &[oj_rc_core::persist::user::PlayerDescriptor], ba_config: oj_rc_core::data::battle_arena_config::BattleArenaData) -> Self { pub fn new(config: &oj_rc_core::data::game_mode::GameModeConfig, map: &oj_rc_core::persist::config::MapConfig, parsers: &oj_rc_core::cubes::CubeParsers, players: &[oj_rc_core::persist::user::PlayerDescriptor], ba_config: oj_rc_core::data::battle_arena_config::BattleArenaData) -> Self {
let cube_parser = parsers.locations_of(); let cube_parser = parsers.locations_of();
let crystals = cube_parser.locations_of_by_distance_to_first(&mut std::io::Cursor::new(&ba_config.base_machine_map), Self::CRYSTAL_ID, Self::CLASP_ID); let crystals = cube_parser.locations_of_by_distance_to_first(&mut std::io::Cursor::new(&ba_config.base_machine_map), Self::CRYSTAL_ID, Self::CLASP_ID);
//let crystals = cube_parser.locations_of_by_distance_from(&mut std::io::Cursor::new(&ba_config.base_machine_map), Self::CRYSTAL_ID, (44, 255, 46));
Self { Self {
respawn_full_heal_duration: config.respawn_full_heal_duration, respawn_full_heal_duration: config.respawn_full_heal_duration,
respawn_heal_duration: config.respawn_heal_duration, respawn_heal_duration: config.respawn_heal_duration,
@@ -1147,7 +1170,7 @@ impl BattleArenaLogic {
} }
} }
async fn do_team_base_stealing(&self, cube_damage: &rlnl::events::ingame::DestroyCubeNoEffect, generic: &crate::matches::GenericGamemodeEngine<Self>, actual_damage_data: impl FnOnce(Vec<rlnl::types::CubeState>) -> crate::matches::RlnlPacket) { async fn do_team_base_stealing(&self, cube_damage: &rlnl::events::ingame::DestroyCubeNoEffect, generic: &crate::matches::GenericGamemodeEngine<Self>, _actual_damage_data: impl FnOnce(Vec<rlnl::types::CubeState>) -> crate::matches::RlnlPacket) {
let base_id = cube_damage.hit_machine_id as u8; let base_id = cube_damage.hit_machine_id as u8;
let mut total_destroyed = 0; let mut total_destroyed = 0;
let mut valid_cubes = Vec::with_capacity(cube_damage.hit_cubes.len()); let mut valid_cubes = Vec::with_capacity(cube_damage.hit_cubes.len());
@@ -1178,30 +1201,49 @@ impl BattleArenaLogic {
}, },
true, true,
).await;*/ ).await;*/
let actual_damage_data = actual_damage_data(valid_cubes); //let actual_damage_data = actual_damage_data(valid_cubes);
generic.broadcast( /*generic.broadcast(
actual_damage_data.event, actual_damage_data.event,
actual_damage_data.property, actual_damage_data.property,
actual_damage_data.data.as_ref(), actual_damage_data.data.as_ref(),
true, true,
).await; ).await;*/
generic.broadcast( /*generic.broadcast(
rlnl::event_code::NetworkEvent::SyncTeamBaseCubes, rlnl::event_code::NetworkEvent::SyncTeamBaseCubes,
literustlib::packet::Property::ReliableOrdered, literustlib::packet::Property::ReliableOrdered,
&base.generate_full_base_heal(base_id, self.config.protonium_health as u32, &self.crystals), &base.generate_full_base_heal(base_id, self.config.protonium_health as u32, &self.crystals),
true, true,
).await; ).await;*/
} }
if total_destroyed != 0 { if total_destroyed != 0 {
if let Some(team_id) = self.player_tracking.team(cube_damage.shooting_machine_id as u8).await { if let Some(team_id) = self.player_tracking.team(cube_damage.shooting_machine_id as u8).await {
if let Some(base) = self.base_tracking.bases.get(&team_id) { if let Some(base) = self.base_tracking.bases.get(&team_id) {
//log::info!("Player {} stole {} crystals", cube_damage.shooting_machine_id, total_destroyed); //log::info!("Player {} stole {} crystals", cube_damage.shooting_machine_id, total_destroyed);
base.cube_index.fetch_add(total_destroyed as f32, std::sync::atomic::Ordering::SeqCst); let total_destroyed_f32 = total_destroyed as f32;
generic.broadcast( let old_float_index = base.cube_index.fetch_add(total_destroyed_f32, std::sync::atomic::Ordering::SeqCst);
let new_float_index = old_float_index + total_destroyed_f32;
let old_index = (old_float_index.ceil() as usize).clamp(0, self.crystals.len());
let new_index = (new_float_index.ceil() as usize).clamp(0, self.crystals.len());
let payload = self.base_tracking.apply_partial_base_heal(
&self.crystals,
self.config.protonium_health as u32,
team_id,
base,
old_index,
new_index,
);
/*generic.broadcast(
rlnl::event_code::NetworkEvent::SyncTeamBaseCubes, rlnl::event_code::NetworkEvent::SyncTeamBaseCubes,
literustlib::packet::Property::ReliableOrdered, literustlib::packet::Property::ReliableOrdered,
&base.generate_full_base_heal(team_id, self.config.protonium_health as u32, &self.crystals), &base.generate_full_base_heal(team_id, self.config.protonium_health as u32, &self.crystals),
true, true,
).await;*/
generic.broadcast(
rlnl::event_code::NetworkEvent::SyncTeamBaseCubes,
literustlib::packet::Property::ReliableOrdered,
&payload,
true,
).await; ).await;
} }
} else { } else {
@@ -1470,7 +1512,7 @@ impl CustomGameLogic for BattleArenaLogic {
} }
}; };
self.do_team_base_stealing(&pseudo, generic, actual_damage_data).await; self.do_team_base_stealing(&pseudo, generic, actual_damage_data).await;
false true
}, },
rlnl::types::TargetType::EqualizerCrystal => { rlnl::types::TargetType::EqualizerCrystal => {
self.do_equalizer_damage(&pseudo, generic).await; self.do_equalizer_damage(&pseudo, generic).await;
@@ -1502,7 +1544,7 @@ impl CustomGameLogic for BattleArenaLogic {
} }
}; };
self.do_team_base_stealing(cube_damage, generic, &actual_damage_data).await; self.do_team_base_stealing(cube_damage, generic, &actual_damage_data).await;
false true
}, },
rlnl::types::TargetType::EqualizerCrystal => { rlnl::types::TargetType::EqualizerCrystal => {
self.do_equalizer_damage(cube_damage, generic).await; self.do_equalizer_damage(cube_damage, generic).await;