Add GamePhase logic
This commit is contained in:
parent
144c7ab5f0
commit
a10698962e
7 changed files with 163 additions and 45 deletions
|
@ -1,12 +1,12 @@
|
||||||
<?xml-model href="../gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
<?xml-model href="../gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||||
<root>
|
<root>
|
||||||
<grid id="grid" x_dim="9" y_dim="1">
|
<grid id="grid" x_dim="11" y_dim="1">
|
||||||
<label id="place" x_slot="0" y_slot="0" text_color="black" text_alignment="right"></label>
|
<label id="place" x_slot="0" y_slot="0" text_color="black" text_alignment="right"></label>
|
||||||
<label
|
<label
|
||||||
id="name"
|
id="name"
|
||||||
x_slot="1" y_slot="0" x_size="6" text_color="black" text_alignment="left"></label>
|
x_slot="1" y_slot="0" x_size="6" text_color="black" text_alignment="left"></label>
|
||||||
<label
|
<label
|
||||||
id="time_behind"
|
id="time"
|
||||||
x_slot="7" y_slot="0" x_size="2" text_color="black" text_alignment="right"></label>
|
x_slot="7" y_slot="0" x_size="4" text_color="black" text_alignment="right"></label>
|
||||||
</grid>
|
</grid>
|
||||||
</root>
|
</root>
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml-model href="../gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
<?xml-model href="../gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||||
<root reference_width="2560" reference_height="1440">
|
<root reference_width="2560" reference_height="1440">
|
||||||
<grid id="main_grid" x_dim="1" y_dim="25" x_offset="10" y_offset="10" width="350" height="875"
|
<grid id="main_grid" x_dim="1" y_dim="25" x_offset="10" y_offset="10" width="400" height="875"
|
||||||
vert_align="top" hori_align="left" margin="0" padding="0"> </grid>
|
vert_align="top" hori_align="left" margin="0" padding="0"> </grid>
|
||||||
</root>
|
</root>
|
|
@ -53,7 +53,14 @@ impl LeaderBoard {
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn race_leaderboard(&mut self, vehicle_scorings: &[VehicleScoringInfoV01]) -> Result<()> {
|
fn update_leaderboard<F>(
|
||||||
|
&mut self,
|
||||||
|
vehicle_scorings: &[VehicleScoringInfoV01],
|
||||||
|
f: F,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
F: Fn(&mut LeaderBoardEntry, &VehicleScoringInfoV01) -> Result<()>,
|
||||||
|
{
|
||||||
for vehicle_scoring in vehicle_scorings {
|
for vehicle_scoring in vehicle_scorings {
|
||||||
let driver_name = Self::c_char_to_string(vehicle_scoring.mDriverName);
|
let driver_name = Self::c_char_to_string(vehicle_scoring.mDriverName);
|
||||||
|
|
||||||
|
@ -69,8 +76,8 @@ impl LeaderBoard {
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.update_place(vehicle_scoring.mPlace)?;
|
entry.update_place(vehicle_scoring.mPlace)?;
|
||||||
entry.update_time_behind_leader(vehicle_scoring.mTimeBehindLeader)?;
|
|
||||||
entry.update_time_behind_next(vehicle_scoring.mTimeBehindNext)?;
|
f(entry, vehicle_scoring)?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let entry = LeaderBoardEntry::new(
|
let entry = LeaderBoardEntry::new(
|
||||||
|
@ -80,6 +87,7 @@ impl LeaderBoard {
|
||||||
vehicle_scoring.mPlace,
|
vehicle_scoring.mPlace,
|
||||||
vehicle_scoring.mTimeBehindLeader,
|
vehicle_scoring.mTimeBehindLeader,
|
||||||
vehicle_scoring.mTimeBehindNext,
|
vehicle_scoring.mTimeBehindNext,
|
||||||
|
vehicle_scoring.mBestLapTime,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.entries.push(entry);
|
self.entries.push(entry);
|
||||||
|
@ -120,19 +128,39 @@ impl LeaderBoard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.entries.is_empty() {
|
|
||||||
self.gui.disable()?;
|
|
||||||
} else {
|
|
||||||
self.gui.enable()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn race_leaderboard(&mut self, vehicle_scorings: &[VehicleScoringInfoV01]) -> Result<()> {
|
||||||
|
self.update_leaderboard(vehicle_scorings, |entry, scoring| {
|
||||||
|
entry.update_time_behind_leader(scoring.mTimeBehindLeader)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quali_leaderboard(&mut self, vehicle_scorings: &[VehicleScoringInfoV01]) -> Result<()> {
|
||||||
|
self.update_leaderboard(vehicle_scorings, |entry, scoring| {
|
||||||
|
entry.update_best_lap(scoring.mBestLapTime)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiOverlay for LeaderBoard {}
|
impl UiOverlay for LeaderBoard {}
|
||||||
|
|
||||||
impl DataReceiver for LeaderBoard {
|
impl DataReceiver for LeaderBoard {
|
||||||
|
fn game_phase_change(&mut self, phase: GamePhase) -> Result<()> {
|
||||||
|
match phase {
|
||||||
|
GamePhase::Practice | GamePhase::Qualifying | GamePhase::Race => self.gui.enable(),
|
||||||
|
_ => self.gui.disable(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_for_phase(&self, phase: GamePhase) -> bool {
|
||||||
|
match phase {
|
||||||
|
GamePhase::Practice | GamePhase::Qualifying | GamePhase::Race => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn scoring_update(
|
fn scoring_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
phase: GamePhase,
|
phase: GamePhase,
|
||||||
|
@ -141,13 +169,13 @@ impl DataReceiver for LeaderBoard {
|
||||||
write_log!("=================== leader board: scoring update ===================");
|
write_log!("=================== leader board: scoring update ===================");
|
||||||
|
|
||||||
match phase {
|
match phase {
|
||||||
GamePhase::TestDay => self.gui.disable()?,
|
GamePhase::Practice | GamePhase::Qualifying => {
|
||||||
GamePhase::Practice => self.gui.disable()?,
|
self.quali_leaderboard(vehicle_scorings)?
|
||||||
GamePhase::Qualifying => self.gui.disable()?,
|
|
||||||
GamePhase::Warmup => self.gui.disable()?,
|
|
||||||
GamePhase::Race => {
|
|
||||||
self.race_leaderboard(vehicle_scorings)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GamePhase::Race => self.race_leaderboard(vehicle_scorings)?,
|
||||||
|
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
write_log!("leader board update finished");
|
write_log!("leader board update finished");
|
||||||
|
@ -177,13 +205,14 @@ struct LeaderBoardEntry {
|
||||||
place: u8,
|
place: u8,
|
||||||
time_behind_leader: f64,
|
time_behind_leader: f64,
|
||||||
time_behind_next: f64,
|
time_behind_next: f64,
|
||||||
|
best_lap: f64,
|
||||||
|
|
||||||
snippet: Arc<GuiSnippet>,
|
snippet: Arc<GuiSnippet>,
|
||||||
|
|
||||||
grid: Arc<Grid>,
|
grid: Arc<Grid>,
|
||||||
name_label: Arc<Label>,
|
name_label: Arc<Label>,
|
||||||
place_label: Arc<Label>,
|
place_label: Arc<Label>,
|
||||||
time_behind_label: Arc<Label>,
|
time_label: Arc<Label>,
|
||||||
|
|
||||||
place_updated: bool,
|
place_updated: bool,
|
||||||
}
|
}
|
||||||
|
@ -196,17 +225,18 @@ impl LeaderBoardEntry {
|
||||||
place: u8,
|
place: u8,
|
||||||
time_behind_leader: f64,
|
time_behind_leader: f64,
|
||||||
time_behind_next: f64,
|
time_behind_next: f64,
|
||||||
|
best_lap: f64,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let snippet = GuiSnippet::from_str(gui_handler, LeaderBoard::ENTRY)?;
|
let snippet = GuiSnippet::from_str(gui_handler, LeaderBoard::ENTRY)?;
|
||||||
|
|
||||||
let background = snippet.element("grid")?;
|
let background = snippet.element("grid")?;
|
||||||
let name_label: Arc<Label> = snippet.element("name")?;
|
let name_label: Arc<Label> = snippet.element("name")?;
|
||||||
let place_label: Arc<Label> = snippet.element("place")?;
|
let place_label: Arc<Label> = snippet.element("place")?;
|
||||||
let time_behind_label: Arc<Label> = snippet.element("time_behind")?;
|
let time_label: Arc<Label> = snippet.element("time")?;
|
||||||
|
|
||||||
name_label.set_text(&name)?;
|
name_label.set_text(&name)?;
|
||||||
place_label.set_text(place)?;
|
place_label.set_text(place)?;
|
||||||
time_behind_label.set_text(format!("{:.3}", time_behind_leader))?;
|
time_label.set_text("---")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id,
|
id,
|
||||||
|
@ -215,13 +245,14 @@ impl LeaderBoardEntry {
|
||||||
place,
|
place,
|
||||||
time_behind_leader,
|
time_behind_leader,
|
||||||
time_behind_next,
|
time_behind_next,
|
||||||
|
best_lap,
|
||||||
|
|
||||||
snippet,
|
snippet,
|
||||||
|
|
||||||
grid: background,
|
grid: background,
|
||||||
name_label,
|
name_label,
|
||||||
place_label,
|
place_label,
|
||||||
time_behind_label,
|
time_label,
|
||||||
|
|
||||||
place_updated: true,
|
place_updated: true,
|
||||||
})
|
})
|
||||||
|
@ -264,21 +295,49 @@ impl LeaderBoardEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_time_behind_leader(&mut self, time: f64) -> Result<()> {
|
pub fn update_time_behind_leader(&mut self, time: f64) -> Result<()> {
|
||||||
self.time_behind_leader = time;
|
if self.time_behind_leader != time {
|
||||||
|
self.time_behind_leader = time;
|
||||||
|
|
||||||
// check if we are leader
|
// check if we are leader
|
||||||
if self.time_behind_leader == 0.0 {
|
if self.time_behind_leader == 0.0 {
|
||||||
self.time_behind_label.set_text("---")
|
self.time_label.set_text("---")?;
|
||||||
} else {
|
} else {
|
||||||
self.time_behind_label
|
self.time_label
|
||||||
.set_text(format!("+{:.3}", self.time_behind_leader))
|
.set_text(format!("+{:.3}", self.time_behind_leader))?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_best_lap(&mut self, time: f64) -> Result<()> {
|
||||||
|
if self.best_lap != time {
|
||||||
|
self.best_lap = time;
|
||||||
|
|
||||||
|
if self.best_lap < 0.0 {
|
||||||
|
self.time_label.set_text("---")?;
|
||||||
|
} else {
|
||||||
|
let text = if self.best_lap > 60.0 {
|
||||||
|
let full_minutes = (self.best_lap / 60.0).floor();
|
||||||
|
let remainder = self.best_lap - (full_minutes * 60.0);
|
||||||
|
|
||||||
|
format!("{:.0}:{:.3}", full_minutes, remainder)
|
||||||
|
} else {
|
||||||
|
format!("{:.3}", self.best_lap)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.time_label.set_text(text)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_time_behind_next(&mut self, time: f64) -> Result<()> {
|
pub fn update_time_behind_next(&mut self, time: f64) -> Result<()> {
|
||||||
self.time_behind_next = time;
|
self.time_behind_next = time;
|
||||||
|
|
||||||
Ok(())
|
self.time_label
|
||||||
|
.set_text(format!("+{:.3}", self.time_behind_next))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn needs_resorting(&self) -> bool {
|
pub fn needs_resorting(&self) -> bool {
|
||||||
|
|
|
@ -231,6 +231,19 @@ impl Pedals {
|
||||||
impl UiOverlay for Pedals {}
|
impl UiOverlay for Pedals {}
|
||||||
|
|
||||||
impl DataReceiver for Pedals {
|
impl DataReceiver for Pedals {
|
||||||
|
fn game_phase_change(&mut self, _phase: GamePhase) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_for_phase(&self, phase: GamePhase) -> bool {
|
||||||
|
match phase {
|
||||||
|
GamePhase::Practice | GamePhase::Qualifying | GamePhase::Race | GamePhase::Warmup => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn scoring_update(
|
fn scoring_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
_phase: GamePhase,
|
_phase: GamePhase,
|
||||||
|
|
|
@ -268,6 +268,19 @@ impl Radar {
|
||||||
impl UiOverlay for Radar {}
|
impl UiOverlay for Radar {}
|
||||||
|
|
||||||
impl DataReceiver for Radar {
|
impl DataReceiver for Radar {
|
||||||
|
fn game_phase_change(&mut self, _phase: GamePhase) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_for_phase(&self, phase: GamePhase) -> bool {
|
||||||
|
match phase {
|
||||||
|
GamePhase::Practice | GamePhase::Qualifying | GamePhase::Race | GamePhase::Warmup => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn scoring_update(
|
fn scoring_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
_phase: GamePhase,
|
_phase: GamePhase,
|
||||||
|
|
|
@ -26,11 +26,7 @@ impl Watermark {
|
||||||
impl UiOverlay for Watermark {}
|
impl UiOverlay for Watermark {}
|
||||||
|
|
||||||
impl DataReceiver for Watermark {
|
impl DataReceiver for Watermark {
|
||||||
fn scoring_update(
|
fn game_phase_change(&mut self, phase: GamePhase) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
phase: GamePhase,
|
|
||||||
_vehicle_scoring: &[VehicleScoringInfoV01],
|
|
||||||
) -> Result<()> {
|
|
||||||
match phase {
|
match phase {
|
||||||
GamePhase::TestDay => self.gui.enable()?,
|
GamePhase::TestDay => self.gui.enable()?,
|
||||||
_ => self.gui.disable()?,
|
_ => self.gui.disable()?,
|
||||||
|
@ -39,6 +35,20 @@ impl DataReceiver for Watermark {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_for_phase(&self, phase: GamePhase) -> bool {
|
||||||
|
match phase {
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scoring_update(
|
||||||
|
&mut self,
|
||||||
|
_phase: GamePhase,
|
||||||
|
_vehicle_scoring: &[VehicleScoringInfoV01],
|
||||||
|
) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn telemetry_update(
|
fn telemetry_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
_player_id: Option<i32>,
|
_player_id: Option<i32>,
|
||||||
|
|
|
@ -8,6 +8,10 @@ use crate::write_log;
|
||||||
use super::UiOverlay;
|
use super::UiOverlay;
|
||||||
|
|
||||||
pub trait DataReceiver {
|
pub trait DataReceiver {
|
||||||
|
fn game_phase_change(&mut self, phase: GamePhase) -> Result<()>;
|
||||||
|
|
||||||
|
fn update_for_phase(&self, phase: GamePhase) -> bool;
|
||||||
|
|
||||||
fn scoring_update(
|
fn scoring_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
phase: GamePhase,
|
phase: GamePhase,
|
||||||
|
@ -21,13 +25,14 @@ pub trait DataReceiver {
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum GamePhase {
|
pub enum GamePhase {
|
||||||
TestDay,
|
TestDay,
|
||||||
Practice,
|
Practice,
|
||||||
Qualifying,
|
Qualifying,
|
||||||
Warmup,
|
Warmup,
|
||||||
Race,
|
Race,
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<i32> for GamePhase {
|
impl TryFrom<i32> for GamePhase {
|
||||||
|
@ -53,6 +58,7 @@ pub struct RFactorData {
|
||||||
|
|
||||||
start_time: Instant,
|
start_time: Instant,
|
||||||
player_id: Option<i32>,
|
player_id: Option<i32>,
|
||||||
|
previous_game_phase: GamePhase,
|
||||||
|
|
||||||
receivers: Vec<Rc<RefCell<dyn UiOverlay>>>,
|
receivers: Vec<Rc<RefCell<dyn UiOverlay>>>,
|
||||||
}
|
}
|
||||||
|
@ -69,6 +75,7 @@ impl RFactorData {
|
||||||
|
|
||||||
start_time,
|
start_time,
|
||||||
player_id: None,
|
player_id: None,
|
||||||
|
previous_game_phase: GamePhase::None,
|
||||||
|
|
||||||
receivers: Vec::new(),
|
receivers: Vec::new(),
|
||||||
})
|
})
|
||||||
|
@ -107,14 +114,28 @@ impl RFactorData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let phase = GamePhase::try_from(scoring_info.mSession)?;
|
{
|
||||||
|
let phase = GamePhase::try_from(scoring_info.mSession)?;
|
||||||
|
|
||||||
write_log!(format!("GamePhase: {:?}", phase));
|
if self.previous_game_phase != phase {
|
||||||
|
self.previous_game_phase = phase;
|
||||||
|
|
||||||
|
for receiver in self.receivers.iter() {
|
||||||
|
receiver
|
||||||
|
.borrow_mut()
|
||||||
|
.game_phase_change(self.previous_game_phase)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_log!(format!("GamePhase: {:?}", self.previous_game_phase));
|
||||||
|
}
|
||||||
|
|
||||||
for receiver in self.receivers.iter() {
|
for receiver in self.receivers.iter() {
|
||||||
receiver
|
let mut rec_mut = receiver.borrow_mut();
|
||||||
.borrow_mut()
|
|
||||||
.scoring_update(phase, &vehicle_scorings)?;
|
if rec_mut.update_for_phase(self.previous_game_phase) {
|
||||||
|
rec_mut.scoring_update(self.previous_game_phase, &vehicle_scorings)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,9 +145,11 @@ impl RFactorData {
|
||||||
write_log!("new telemetry update");
|
write_log!("new telemetry update");
|
||||||
|
|
||||||
for receiver in self.receivers.iter() {
|
for receiver in self.receivers.iter() {
|
||||||
receiver
|
let mut rec_mut = receiver.borrow_mut();
|
||||||
.borrow_mut()
|
|
||||||
.telemetry_update(self.player_id, &telemetries)?;
|
if rec_mut.update_for_phase(self.previous_game_phase) {
|
||||||
|
rec_mut.telemetry_update(self.player_id, &telemetries)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue