1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
use std::{fmt::Display, str::FromStr};
use crate::ParseError;
#[derive(Debug)]
pub struct Event {
pub kind: EventKind,
pub params: Vec<String>,
pub text: Option<String>,
}
#[derive(Debug)]
pub enum EventKind {
/// Generic event.
Message,
/// Bookmarks are highlighted in the time line and in the event log. They are easy to spot and
/// handy to highlight parts of the flight, like a bombing run, or when the trainee was in her
/// final approach for landing.
Bookmark,
/// Debug events are highlighted and easy to spot in the timeline and event log. Because they
/// must be used for development purposes, they are displayed only when launching Tacview with
/// the command line argument /Debug:on
Debug,
/// This event is useful to specify when an aircraft (or any object) is cleanly removed from the
/// battlefield (not destroyed). This prevents Tacview from generating a Destroyed event by
/// error.
LeftArea,
/// When an object has been officially destroyed.
Destroyed,
/// Because Tacview may not always properly auto-detect take-off events, it can be useful to
/// manually inject this event in the flight recording.
TakenOff,
/// Because Tacview may not always properly auto-detect landing events, it can be useful to
/// manually inject this event in the flight recording.
Landed,
/// Mainly used for real-life training debriefing to specify when a weapon (typically a
/// missile) reaches or misses its target. Tacview will report in the shot log as well as in the
/// 3D view the result of the shot. Most parameters are optional. SourceId designates the object
/// which has fired the weapon, while TargetId designates the target. Even if the displayed
/// result may be in nautical miles, bullseye coordinates must be specified in meters. The
/// target must be explicitly (manually) destroyed or disabled using the appropriate properties
/// independently from this event.
Timeout,
/// Unknown event. This only exists for forward compatibility and using it is not recommended
/// as the event you are using could be move to the known event in a future release.
Unknown(String),
}
impl FromStr for Event {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split('|');
let kind = parts.next().ok_or(ParseError::InvalidEvent)?;
let kind = match kind {
"Message" => EventKind::Message,
"Bookmark" => EventKind::Bookmark,
"Debug" => EventKind::Debug,
"LeftArea" => EventKind::LeftArea,
"Destroyed" => EventKind::Destroyed,
"TakenOff" => EventKind::TakenOff,
"Landed" => EventKind::Landed,
"Timeout" => EventKind::Timeout,
name => EventKind::Unknown(name.to_string()),
};
let mut params = parts.map(String::from).collect::<Vec<_>>();
let text = if params.is_empty() {
None
} else {
Some(params.remove(params.len() - 1)).filter(|s| !s.is_empty())
};
Ok(Event { kind, params, text })
}
}
impl Display for Event {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "0,Event={}", self.kind.as_str())?;
for param in &self.params {
write!(f, "|{}", param)?;
}
write!(f, "|{}", self.text.as_deref().unwrap_or_default())?;
Ok(())
}
}
impl EventKind {
fn as_str(&self) -> &str {
use EventKind::*;
match self {
Message => "Message",
Bookmark => "Bookmark",
Debug => "Debug",
LeftArea => "LeftArea",
Destroyed => "Destroyed",
TakenOff => "TakenOff",
Landed => "Landed",
Timeout => "Timeout",
Unknown(name) => name,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_event_text() {
assert_eq!(
Event {
kind: EventKind::Landed,
params: vec!["1".to_string(), "2".to_string()],
text: None,
}
.to_string(),
"0,Event=Landed|1|2|"
)
}
}