mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Init BA base crystal order on startup if possible, change it occasionally
This commit is contained in:
@@ -177,6 +177,21 @@ impl CubeLocationsParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn locations_of_reactor_sort(&self, r: &mut dyn std::io::Read) -> Vec<CubeLocationInfo> {
|
pub fn locations_of_reactor_sort(&self, r: &mut dyn std::io::Read) -> Vec<CubeLocationInfo> {
|
||||||
|
self.locations_of_reactor_sort_custom(r, 32, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate sorted crystal cube list using custom thresholds
|
||||||
|
///
|
||||||
|
/// `bail_after_iters` is the maximum loops to attempt before giving up trying to sort the vehicle's cubes.
|
||||||
|
/// Decreasing this guarantees a faster function return but increases the risk of the result being incomplete.
|
||||||
|
/// In the game client, an incomplete result will cause the match to end at a base charge lower than 100%.
|
||||||
|
///
|
||||||
|
/// `deterministic_after_iters` is the maxiumum initial loops to allow for random connection traversal.
|
||||||
|
/// Decreasing this makes the crystal order more consistent and makes the function return faster.
|
||||||
|
/// Increasing this makes the crystal order more random and interesting but usually requires more iterations (slower).
|
||||||
|
///
|
||||||
|
/// Usually, this algorithm takes `deterministic_after_iters + 2` iterations to complete.
|
||||||
|
pub fn locations_of_reactor_sort_custom(&self, r: &mut dyn std::io::Read, bail_after_iters: usize, deterministic_after_iters: usize) -> Vec<CubeLocationInfo> {
|
||||||
use super::{CUBE_CONNECTIONS, CUBE_ROTATIONS};
|
use super::{CUBE_CONNECTIONS, CUBE_ROTATIONS};
|
||||||
match super::parser::Cube::parse_list(r) {
|
match super::parser::Cube::parse_list(r) {
|
||||||
Ok(cubes) => {
|
Ok(cubes) => {
|
||||||
@@ -223,15 +238,15 @@ impl CubeLocationsParser {
|
|||||||
let mut iteration = 0;
|
let mut iteration = 0;
|
||||||
let mut random = rand::rng();
|
let mut random = rand::rng();
|
||||||
let mut to_be_released = Vec::new();
|
let mut to_be_released = Vec::new();
|
||||||
while !to_be_sorted.is_empty() && iteration < 32 {
|
while !to_be_sorted.is_empty() && iteration < bail_after_iters {
|
||||||
for (cube_i, calc_conns) in to_be_sorted.iter() {
|
for (cube_i, calc_conns) in to_be_sorted.iter() {
|
||||||
let connection = is_sharing_connection(calc_conns, &available_faces)
|
let connection = is_sharing_connection(calc_conns, &available_faces)
|
||||||
.and_then(|(cube_face_i, face_available_i)| {
|
.and_then(|(cube_face_i, face_available_i)| {
|
||||||
use rand::Rng;
|
|
||||||
if face_available_i < connected_to_connections.connections.len() && sorted.len() < connected_to_connections.connections.len() {
|
if face_available_i < connected_to_connections.connections.len() && sorted.len() < connected_to_connections.connections.len() {
|
||||||
// prioritize finding all target connections first
|
// prioritize finding all target connections first
|
||||||
Some((cube_face_i, face_available_i))
|
Some((cube_face_i, face_available_i))
|
||||||
} else if iteration < 3 || (face_available_i >= connected_to_connections.connections.len() && sorted.len() < connected_to_connections.connections.len()) {
|
} else if iteration < deterministic_after_iters || (face_available_i >= connected_to_connections.connections.len() && sorted.len() < connected_to_connections.connections.len()) {
|
||||||
|
use rand::Rng;
|
||||||
let random_face = random.random_range(0..calc_conns.len());
|
let random_face = random.random_range(0..calc_conns.len());
|
||||||
if cube_face_i >= random_face {
|
if cube_face_i >= random_face {
|
||||||
Some((cube_face_i, face_available_i))
|
Some((cube_face_i, face_available_i))
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mod cubes_json;
|
|||||||
pub use cubes_json::CubeConfig;
|
pub use cubes_json::CubeConfig;
|
||||||
|
|
||||||
mod traits;
|
mod traits;
|
||||||
pub use traits::{ConfigProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode, Point, Sphere, MapConfig, LinksConfig, FakePlayer, ClientEmulator, EnergyConfig, BattleArenaResolver, PitSettings, PitWinCondition, TeamDeathMatchSettings, ShopEntriesResolver, ShopAction, ShopGain, PromoCode, MultiplayerSettings};
|
pub use traits::{ConfigProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode, Point, Sphere, MapConfig, LinksConfig, FakePlayer, ClientEmulator, EnergyConfig, BattleArenaResolver, PitSettings, PitWinCondition, TeamDeathMatchSettings, ShopEntriesResolver, ShopAction, ShopGain, PromoCode, MultiplayerSettings, BattleArenaCrystalParams};
|
||||||
|
|
||||||
mod validation;
|
mod validation;
|
||||||
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};
|
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};
|
||||||
|
|||||||
@@ -412,6 +412,28 @@ impl BattleArenaResolver {
|
|||||||
],
|
],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_base_machine_immediate_early(&self) -> Option<Vec<u8>> {
|
||||||
|
match &self.data.base.id {
|
||||||
|
crate::persist::PrefabId::Raw { cube_data, .. } => {
|
||||||
|
Some(cube_data.to_owned())
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crystal_sort_params(&self) -> BattleArenaCrystalParams {
|
||||||
|
BattleArenaCrystalParams {
|
||||||
|
max_iterations: self.data.max_base_iterations as usize,
|
||||||
|
max_random_iterations: self.data.max_base_random_iterations as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BattleArenaCrystalParams {
|
||||||
|
pub max_iterations: usize,
|
||||||
|
pub max_random_iterations: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
implementation: ClientEmulation::ClientAI,
|
implementation: ClientEmulation::ClientAI,
|
||||||
},*/
|
},
|
||||||
/*FakePlayerConf {
|
FakePlayerConf {
|
||||||
team: None,
|
team: None,
|
||||||
vehicle: super::garage::PrefabVehicle {
|
vehicle: super::garage::PrefabVehicle {
|
||||||
name: Some("fake3".to_owned()),
|
name: Some("fake3".to_owned()),
|
||||||
@@ -221,6 +221,54 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
implementation: ClientEmulation::ClientAI,
|
implementation: ClientEmulation::ClientAI,
|
||||||
|
},
|
||||||
|
FakePlayerConf {
|
||||||
|
team: None,
|
||||||
|
vehicle: super::garage::PrefabVehicle {
|
||||||
|
name: Some("fake5".to_owned()),
|
||||||
|
username: "Server5".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: None,
|
||||||
|
vehicle: super::garage::PrefabVehicle {
|
||||||
|
name: Some("fake6".to_owned()),
|
||||||
|
username: "Server6".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: None,
|
||||||
|
vehicle: super::garage::PrefabVehicle {
|
||||||
|
name: Some("fake7".to_owned()),
|
||||||
|
username: "Server7".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: None,
|
||||||
|
vehicle: super::garage::PrefabVehicle {
|
||||||
|
name: Some("fake8".to_owned()),
|
||||||
|
username: "Server8".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,
|
||||||
},*/
|
},*/
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -313,6 +361,10 @@ pub struct BattleArenaConfig {
|
|||||||
pub base: super::garage::PrefabVehicle,
|
pub base: super::garage::PrefabVehicle,
|
||||||
#[serde(default = "default_segments")]
|
#[serde(default = "default_segments")]
|
||||||
pub num_segments: u16,
|
pub num_segments: u16,
|
||||||
|
#[serde(default = "default_max_base_iterations")]
|
||||||
|
pub max_base_iterations: u32,
|
||||||
|
#[serde(default = "default_max_base_random_iterations")]
|
||||||
|
pub max_base_random_iterations: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn default_ba_conf() -> BattleArenaConfig {
|
pub(super) fn default_ba_conf() -> BattleArenaConfig {
|
||||||
@@ -326,6 +378,8 @@ pub(super) fn default_ba_conf() -> BattleArenaConfig {
|
|||||||
equalizer_duration_s: default_equalizer_duration(),
|
equalizer_duration_s: default_equalizer_duration(),
|
||||||
base: default_ba_base(),
|
base: default_ba_base(),
|
||||||
num_segments: default_segments(),
|
num_segments: default_segments(),
|
||||||
|
max_base_iterations: default_max_base_iterations(),
|
||||||
|
max_base_random_iterations: default_max_base_random_iterations(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,6 +432,14 @@ fn default_segments() -> u16 {
|
|||||||
3
|
3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_max_base_iterations() -> u32 {
|
||||||
|
64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_max_base_random_iterations() -> u32 {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum PitWinCondition {
|
pub enum PitWinCondition {
|
||||||
|
|||||||
@@ -5,16 +5,19 @@ pub struct GameMatches {
|
|||||||
map_configs: std::collections::HashMap<String, oj_rc_core::persist::config::MapConfig>,
|
map_configs: std::collections::HashMap<String, oj_rc_core::persist::config::MapConfig>,
|
||||||
//fake_players: Vec<oj_rc_core::persist::config::FakePlayer>,
|
//fake_players: Vec<oj_rc_core::persist::config::FakePlayer>,
|
||||||
cube_parsers: std::sync::Arc<oj_rc_core::cubes::CubeParsers>,
|
cube_parsers: std::sync::Arc<oj_rc_core::cubes::CubeParsers>,
|
||||||
ba_sorted_crystals: tokio::sync::RwLock<std::sync::Arc<Vec<oj_rc_core::cubes::CubeLocationInfo>>>, // cached after first calculation
|
ba_sorted_crystals: std::sync::Arc<tokio::sync::RwLock<std::sync::Arc<Vec<oj_rc_core::cubes::CubeLocationInfo>>>>, // cached after first calculation
|
||||||
ba_settings: std::sync::Arc<oj_rc_core::persist::config::BattleArenaResolver>,
|
ba_settings: std::sync::Arc<oj_rc_core::persist::config::BattleArenaResolver>,
|
||||||
pit_settings: std::sync::Arc<oj_rc_core::persist::config::PitSettings>,
|
pit_settings: std::sync::Arc<oj_rc_core::persist::config::PitSettings>,
|
||||||
tdm_settings: std::sync::Arc<oj_rc_core::persist::config::TeamDeathMatchSettings>,
|
tdm_settings: std::sync::Arc<oj_rc_core::persist::config::TeamDeathMatchSettings>,
|
||||||
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||||
mp_settings: std::sync::Arc<oj_rc_core::persist::config::MultiplayerSettings>,
|
mp_settings: std::sync::Arc<oj_rc_core::persist::config::MultiplayerSettings>,
|
||||||
|
is_crystal_regen_running: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameMatches {
|
impl GameMatches {
|
||||||
pub fn new(conf: &oj_rc_core::persist::config::ConfigImpl, cube_parsers: std::sync::Arc<oj_rc_core::cubes::CubeParsers>, factory: std::sync::Arc<oj_rc_core::factory::Factory>) -> Self {
|
pub fn new(conf: &oj_rc_core::persist::config::ConfigImpl, cube_parsers: std::sync::Arc<oj_rc_core::cubes::CubeParsers>, factory: std::sync::Arc<oj_rc_core::factory::Factory>) -> Self {
|
||||||
|
let ba_settings = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::ba_settings(conf));
|
||||||
|
let ba_sorted_crystals = std::sync::Arc::new(Self::maybe_init_ba_sorted_crystals(&ba_settings, &cube_parsers));
|
||||||
Self {
|
Self {
|
||||||
matches: std::collections::HashMap::new(),
|
matches: std::collections::HashMap::new(),
|
||||||
routing: std::collections::HashMap::new(),
|
routing: std::collections::HashMap::new(),
|
||||||
@@ -25,15 +28,44 @@ impl GameMatches {
|
|||||||
.collect(),
|
.collect(),
|
||||||
//fake_players: <oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::fake_players(conf),
|
//fake_players: <oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::fake_players(conf),
|
||||||
cube_parsers,
|
cube_parsers,
|
||||||
ba_sorted_crystals: tokio::sync::RwLock::new(std::sync::Arc::new(Vec::default())),
|
ba_sorted_crystals,
|
||||||
ba_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::ba_settings(conf)),
|
ba_settings,
|
||||||
pit_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::pit_settings(conf)),
|
pit_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::pit_settings(conf)),
|
||||||
tdm_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::tdm_settings(conf)),
|
tdm_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::tdm_settings(conf)),
|
||||||
factory,
|
factory,
|
||||||
mp_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::multiplayer_settings(conf)),
|
mp_settings: std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::multiplayer_settings(conf)),
|
||||||
|
is_crystal_regen_running: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe_init_ba_sorted_crystals(ba_conf: &oj_rc_core::persist::config::BattleArenaResolver, cube_parsers: &oj_rc_core::cubes::CubeParsers) -> tokio::sync::RwLock<std::sync::Arc<Vec<oj_rc_core::cubes::CubeLocationInfo>>> {
|
||||||
|
if let Some(base_machine_map) = ba_conf.resolve_base_machine_immediate_early() {
|
||||||
|
let gen_start = chrono::Utc::now();
|
||||||
|
let gen_params = ba_conf.crystal_sort_params();
|
||||||
|
let crystals = Self::generate_ordered_crystal_list(&gen_params, cube_parsers, &base_machine_map);
|
||||||
|
let gen_end = chrono::Utc::now();
|
||||||
|
let delta = gen_end.signed_duration_since(gen_start);
|
||||||
|
log::info!("Early base crystal list initialization took {}ms for {} crystals", delta.num_milliseconds(), crystals.len());
|
||||||
|
tokio::sync::RwLock::new(std::sync::Arc::new(crystals))
|
||||||
|
} else {
|
||||||
|
log::warn!("First Batte Arena match will take longer to initialization due to non-raw base machine");
|
||||||
|
tokio::sync::RwLock::new(std::sync::Arc::new(Vec::default()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_ordered_crystal_list(
|
||||||
|
gen_params: &oj_rc_core::persist::config::BattleArenaCrystalParams,
|
||||||
|
cube_parsers: &oj_rc_core::cubes::CubeParsers,
|
||||||
|
vehicle_data: &[u8],
|
||||||
|
) -> Vec<oj_rc_core::cubes::CubeLocationInfo> {
|
||||||
|
cube_parsers.locations_of()
|
||||||
|
.locations_of_reactor_sort_custom(
|
||||||
|
&mut std::io::Cursor::new(vehicle_data),
|
||||||
|
gen_params.max_iterations,
|
||||||
|
gen_params.max_random_iterations,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn(self) -> tokio::sync::mpsc::Sender<super::GameMessage> {
|
pub fn spawn(self) -> tokio::sync::mpsc::Sender<super::GameMessage> {
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel(super::CHANNEL_BOUND);
|
let (tx, rx) = tokio::sync::mpsc::channel(super::CHANNEL_BOUND);
|
||||||
tokio::spawn(self.run(rx));
|
tokio::spawn(self.run(rx));
|
||||||
@@ -117,6 +149,8 @@ impl GameMatches {
|
|||||||
})?;
|
})?;
|
||||||
let crystals = if self.ba_sorted_crystals.read().await.is_empty() {
|
let crystals = if self.ba_sorted_crystals.read().await.is_empty() {
|
||||||
let crystals = std::sync::Arc::new(
|
let crystals = std::sync::Arc::new(
|
||||||
|
// NOTE: this uses default (lower) crystal sort params to prevent sorting from taking too long
|
||||||
|
// if this takes too long, players can be disconnected from the multiplayer due to client timeout
|
||||||
self.cube_parsers.locations_of()
|
self.cube_parsers.locations_of()
|
||||||
.locations_of_reactor_sort(&mut std::io::Cursor::new(&resolved_ba_conf.base_machine_map))
|
.locations_of_reactor_sort(&mut std::io::Cursor::new(&resolved_ba_conf.base_machine_map))
|
||||||
);
|
);
|
||||||
@@ -207,6 +241,16 @@ impl GameMatches {
|
|||||||
};
|
};
|
||||||
self.matches.insert(game_guid.clone(), tx.clone());
|
self.matches.insert(game_guid.clone(), tx.clone());
|
||||||
self.routing.insert(user.user_id(), game_guid.clone());
|
self.routing.insert(user.user_id(), game_guid.clone());
|
||||||
|
if !self.is_crystal_regen_running.swap(true, std::sync::atomic::Ordering::SeqCst) {
|
||||||
|
tokio::task::spawn(Self::regenerate_crystal_order_task(
|
||||||
|
self.ba_sorted_crystals.clone(),
|
||||||
|
self.cube_parsers.clone(),
|
||||||
|
self.factory.clone(),
|
||||||
|
self.ba_settings.clone(),
|
||||||
|
user.clone(),
|
||||||
|
self.is_crystal_regen_running.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
if tx.send(super::GameMessage::NewConnection { user, game_guid, connection, response, sender }).await.is_err() {
|
if tx.send(super::GameMessage::NewConnection { user, game_guid, connection, response, sender }).await.is_err() {
|
||||||
log::error!("Failed to send NewConnection game message to new match");
|
log::error!("Failed to send NewConnection game message to new match");
|
||||||
}
|
}
|
||||||
@@ -275,4 +319,56 @@ impl GameMatches {
|
|||||||
}
|
}
|
||||||
log::warn!("Match message router has completed");
|
log::warn!("Match message router has completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn regenerate_crystal_order_task(
|
||||||
|
crystal_order: std::sync::Arc<tokio::sync::RwLock<std::sync::Arc<Vec<oj_rc_core::cubes::CubeLocationInfo>>>>,
|
||||||
|
parsers: std::sync::Arc<oj_rc_core::cubes::CubeParsers>,
|
||||||
|
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||||
|
ba_resolver: std::sync::Arc<oj_rc_core::persist::config::BattleArenaResolver>,
|
||||||
|
user: std::sync::Arc<Box<dyn oj_rc_core::persist::user::MultiplayerUser + Send + Sync + 'static>>,
|
||||||
|
tracker: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
||||||
|
) {
|
||||||
|
//tracker.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||||
|
let ba_resolved_result = ba_resolver.resolve(
|
||||||
|
user.as_ref().as_ref(),
|
||||||
|
factory.as_ref(),
|
||||||
|
parsers.weapon_order().as_ref(),
|
||||||
|
parsers.cpu_counter().as_ref(),
|
||||||
|
).await;
|
||||||
|
match ba_resolved_result {
|
||||||
|
Ok(ba_resolved) => {
|
||||||
|
log::info!("Regenerate crystal order task started successfully, task sleeping for now");
|
||||||
|
// wait a long while to prevent this from interfering with the match's startup
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(5 * 60)).await; // 5 minutes
|
||||||
|
let gen_start = chrono::Utc::now();
|
||||||
|
let new_order_result = tokio::task::spawn_blocking(move || {
|
||||||
|
Self::generate_ordered_crystal_list(
|
||||||
|
&ba_resolver.crystal_sort_params(),
|
||||||
|
parsers.as_ref(),
|
||||||
|
&ba_resolved.base_machine_map,
|
||||||
|
)
|
||||||
|
}).await;
|
||||||
|
match new_order_result {
|
||||||
|
Ok(new_order) => {
|
||||||
|
let gen_end = chrono::Utc::now();
|
||||||
|
let delta = gen_end.signed_duration_since(gen_start);
|
||||||
|
log::info!("Base crystal order re-gen took {}ms for {} crystals", delta.num_milliseconds(), new_order.len());
|
||||||
|
*crystal_order.write().await = std::sync::Arc::new(new_order);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to regenerate crystal order: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
if let Some(e_msg) = e.error_msg() {
|
||||||
|
log::error!("Failed to regenerate crystal order: {} ({})", e_msg, e.error_code());
|
||||||
|
} else {
|
||||||
|
log::error!("Failed to regenerate crystal order ({})", e.error_code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tracker.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user