Rehost selected-year bucket scalar ladder

This commit is contained in:
Jan Petykiewicz 2026-04-18 06:59:06 -07:00
commit f9b3cf8571
10 changed files with 295 additions and 9 deletions

View file

@ -34,6 +34,7 @@ pub const REQUIRED_EXPORTS: &[&str] = &[
"artifacts/exports/rt3-1.06/event-effects-cargo-bindings.json",
"artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json",
"artifacts/exports/rt3-1.06/economy-cargo-sources.json",
"artifacts/exports/rt3-1.06/selected-year-bucket-ladder.json",
];
pub const REQUIRED_ATLAS_HEADINGS: &[&str] = &[

View file

@ -982,6 +982,8 @@ fn project_save_slice_components(
.cached_available_locomotive_rating_value_f32_text
.clone()
}),
selected_year_bucket_scalar_raw_u32: None,
selected_year_bucket_scalar_value_f32_text: None,
selected_year_gap_scalar_raw_u32: None,
selected_year_gap_scalar_value_f32_text: None,
absolute_counter_restore_kind: Some(
@ -6448,7 +6450,7 @@ mod tests {
);
assert_eq!(
import.state.world_restore.economic_tuning_mirror_raw_u32,
Some(0x3f46d093)
Some(0x3f400000)
);
assert_eq!(
import
@ -6456,7 +6458,7 @@ mod tests {
.world_restore
.economic_tuning_mirror_value_f32_text
.as_deref(),
Some("0.776620")
Some("0.750000")
);
assert_eq!(
import.state.world_restore.economic_tuning_lane_raw_u32,

View file

@ -1,4 +1,5 @@
use std::collections::{BTreeMap, BTreeSet};
use std::sync::OnceLock;
use serde::{Deserialize, Serialize};
@ -1418,6 +1419,10 @@ pub struct RuntimeWorldRestoreState {
#[serde(default)]
pub cached_available_locomotive_rating_value_f32_text: Option<String>,
#[serde(default)]
pub selected_year_bucket_scalar_raw_u32: Option<u32>,
#[serde(default)]
pub selected_year_bucket_scalar_value_f32_text: Option<String>,
#[serde(default)]
pub selected_year_gap_scalar_raw_u32: Option<u32>,
#[serde(default)]
pub selected_year_gap_scalar_value_f32_text: Option<String>,
@ -2396,6 +2401,11 @@ impl RuntimeState {
.world_restore
.all_electric_locomotives_available_raw_u8
.map(|raw| raw != 0);
if let Some(&lane_0_raw_u32) = self.world_restore.economic_tuning_lane_raw_u32.first() {
self.world_restore.economic_tuning_mirror_raw_u32 = Some(lane_0_raw_u32);
self.world_restore.economic_tuning_mirror_value_f32_text =
Some(format!("{:.6}", f32::from_bits(lane_0_raw_u32)));
}
let year_word = self
.world_restore
.packed_year_word_raw_u16
@ -2409,6 +2419,11 @@ impl RuntimeState {
})
})
.unwrap_or(self.calendar.year);
if let Some(value) = runtime_world_selected_year_bucket_scalar_from_year_word(year_word) {
self.world_restore.selected_year_bucket_scalar_raw_u32 = Some(value.to_bits());
self.world_restore
.selected_year_bucket_scalar_value_f32_text = Some(format!("{value:.6}"));
}
if let Some(value) = runtime_world_selected_year_gap_scalar_from_year_word(year_word) {
self.world_restore.selected_year_gap_scalar_raw_u32 = Some(value.to_bits());
self.world_restore.selected_year_gap_scalar_value_f32_text =
@ -2438,6 +2453,53 @@ impl RuntimeState {
}
}
#[derive(Debug, Clone, Deserialize)]
struct CheckedInSelectedYearBucketLadderArtifact {
entries: Vec<CheckedInSelectedYearBucketLadderEntry>,
}
#[derive(Debug, Clone, Deserialize)]
struct CheckedInSelectedYearBucketLadderEntry {
year: u32,
value: f32,
}
fn checked_in_selected_year_bucket_ladder() -> &'static [CheckedInSelectedYearBucketLadderEntry] {
static LADDER: OnceLock<Vec<CheckedInSelectedYearBucketLadderEntry>> = OnceLock::new();
LADDER
.get_or_init(|| {
serde_json::from_str::<CheckedInSelectedYearBucketLadderArtifact>(include_str!(
"../../../artifacts/exports/rt3-1.06/selected-year-bucket-ladder.json"
))
.expect("checked-in selected-year bucket ladder should parse")
.entries
})
.as_slice()
}
pub fn runtime_world_selected_year_bucket_scalar_from_year_word(year_word: u32) -> Option<f32> {
let ladder = checked_in_selected_year_bucket_ladder();
if ladder.is_empty() {
return None;
}
if year_word <= ladder[0].year {
return Some(ladder[0].value);
}
for window in ladder.windows(2) {
let start = &window[0];
let end = &window[1];
if year_word <= end.year {
if year_word <= start.year || end.year == start.year {
return Some(start.value);
}
let span = (end.year - start.year) as f32;
let progress = (year_word - start.year) as f32 / span;
return Some(start.value + (end.value - start.value) * progress);
}
}
ladder.last().map(|entry| entry.value)
}
pub fn runtime_world_selected_year_gap_scalar_from_year_word(year_word: u32) -> Option<f32> {
let normalized = (year_word as f64 - 1850.0) / 150.0;
if !normalized.is_finite() {
@ -5070,6 +5132,8 @@ mod tests {
economic_tuning_mirror_value_f32_text: None,
economic_tuning_lane_raw_u32: Vec::new(),
economic_tuning_lane_value_f32_text: Vec::new(),
selected_year_bucket_scalar_raw_u32: None,
selected_year_bucket_scalar_value_f32_text: None,
selected_year_gap_scalar_raw_u32: None,
selected_year_gap_scalar_value_f32_text: None,
absolute_counter_restore_kind: Some(
@ -8060,6 +8124,18 @@ mod tests {
#[test]
fn derives_selected_year_gap_scalar_from_year_word() {
assert_eq!(
runtime_world_selected_year_bucket_scalar_from_year_word(1830),
Some(25.0)
);
assert_eq!(
runtime_world_selected_year_bucket_scalar_from_year_word(1835),
Some(31.5)
);
assert_eq!(
runtime_world_selected_year_bucket_scalar_from_year_word(2000),
Some(123.0)
);
assert_eq!(
runtime_world_selected_year_gap_scalar_from_year_word(1830),
Some((1.0f32 / 3.0).clamp(1.0 / 3.0, 1.0))
@ -8087,6 +8163,7 @@ mod tests {
save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState {
packed_year_word_raw_u16: Some(1900),
economic_tuning_lane_raw_u32: vec![0x3f400000],
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(),
@ -8125,6 +8202,28 @@ mod tests {
state.refresh_derived_world_state();
assert_eq!(
state.world_restore.economic_tuning_mirror_raw_u32,
Some(0x3f400000)
);
assert_eq!(
state
.world_restore
.economic_tuning_mirror_value_f32_text
.as_deref(),
Some("0.750000")
);
assert_eq!(
state.world_restore.selected_year_bucket_scalar_raw_u32,
Some(70.0f32.to_bits())
);
assert_eq!(
state
.world_restore
.selected_year_bucket_scalar_value_f32_text
.as_deref(),
Some("70.000000")
);
assert_eq!(
state.world_restore.selected_year_gap_scalar_raw_u32,
Some(((50.0f32 / 150.0).clamp(1.0 / 3.0, 1.0)).to_bits())

View file

@ -80,6 +80,8 @@ pub struct RuntimeSummary {
pub world_restore_economic_tuning_lane_value_f32_text: Vec<String>,
pub world_restore_cached_available_locomotive_rating_raw_u32: Option<u32>,
pub world_restore_cached_available_locomotive_rating_value_f32_text: Option<String>,
pub world_restore_selected_year_bucket_scalar_raw_u32: Option<u32>,
pub world_restore_selected_year_bucket_scalar_value_f32_text: Option<String>,
pub world_restore_selected_year_gap_scalar_raw_u32: Option<u32>,
pub world_restore_selected_year_gap_scalar_value_f32_text: Option<String>,
pub world_restore_absolute_counter_restore_kind: Option<String>,
@ -471,6 +473,13 @@ impl RuntimeSummary {
.world_restore
.cached_available_locomotive_rating_value_f32_text
.clone(),
world_restore_selected_year_bucket_scalar_raw_u32: state
.world_restore
.selected_year_bucket_scalar_raw_u32,
world_restore_selected_year_bucket_scalar_value_f32_text: state
.world_restore
.selected_year_bucket_scalar_value_f32_text
.clone(),
world_restore_selected_year_gap_scalar_raw_u32: state
.world_restore
.selected_year_gap_scalar_raw_u32,
@ -1807,6 +1816,8 @@ mod tests {
all_electric_locomotives_available_enabled: Some(true),
cached_available_locomotive_rating_raw_u32: Some(0x41a00000),
cached_available_locomotive_rating_value_f32_text: Some("20.000000".to_string()),
selected_year_bucket_scalar_raw_u32: Some(25.0f32.to_bits()),
selected_year_bucket_scalar_value_f32_text: Some("25.000000".to_string()),
selected_year_gap_scalar_raw_u32: Some(0x3eaaaaab),
selected_year_gap_scalar_value_f32_text: Some("0.333333".to_string()),
..RuntimeWorldRestoreState::default()
@ -1961,6 +1972,16 @@ mod tests {
.as_deref(),
Some("20.000000")
);
assert_eq!(
summary.world_restore_selected_year_bucket_scalar_raw_u32,
Some(25.0f32.to_bits())
);
assert_eq!(
summary
.world_restore_selected_year_bucket_scalar_value_f32_text
.as_deref(),
Some("25.000000")
);
assert_eq!(summary.world_restore_economic_tuning_lane_count, 6);
assert_eq!(
summary.world_restore_economic_tuning_lane_value_f32_text,