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
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)?;
}
if let Some(text) = &self.text {
write!(f, "|{}", text)?;
}
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,
}
}
}