1
0
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:
NG (Graham)
2026-02-07 17:47:14 -05:00
parent 08d7f86dcb
commit 93beb1b4e7
5 changed files with 204 additions and 9 deletions

View File

@@ -177,6 +177,21 @@ impl CubeLocationsParser {
}
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};
match super::parser::Cube::parse_list(r) {
Ok(cubes) => {
@@ -223,15 +238,15 @@ impl CubeLocationsParser {
let mut iteration = 0;
let mut random = rand::rng();
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() {
let connection = is_sharing_connection(calc_conns, &available_faces)
.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() {
// prioritize finding all target connections first
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());
if cube_face_i >= random_face {
Some((cube_face_i, face_available_i))

View File

@@ -2,7 +2,7 @@ mod cubes_json;
pub use cubes_json::CubeConfig;
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;
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};

View File

@@ -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)]

View File

@@ -197,8 +197,8 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
},
},
implementation: ClientEmulation::ClientAI,
},*/
/*FakePlayerConf {
},
FakePlayerConf {
team: None,
vehicle: super::garage::PrefabVehicle {
name: Some("fake3".to_owned()),
@@ -221,6 +221,54 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
},
},
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,
#[serde(default = "default_segments")]
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 {
@@ -326,6 +378,8 @@ pub(super) fn default_ba_conf() -> BattleArenaConfig {
equalizer_duration_s: default_equalizer_duration(),
base: default_ba_base(),
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
}
fn default_max_base_iterations() -> u32 {
64
}
fn default_max_base_random_iterations() -> u32 {
3
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
pub enum PitWinCondition {