|
|
@ -158,7 +158,7 @@ fn get_match(divisions: &mut HashMap<i32, Division>, tuple: MatchTuple) -> Optio
|
|
|
|
None => {},
|
|
|
|
None => {},
|
|
|
|
Some(division) => {
|
|
|
|
Some(division) => {
|
|
|
|
for m in &mut division.matches {
|
|
|
|
for m in &mut division.matches {
|
|
|
|
if m.tuple == tuple {
|
|
|
|
if m.info.tuple == tuple {
|
|
|
|
return Some(m);
|
|
|
|
return Some(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -233,7 +233,7 @@ impl Event {
|
|
|
|
start: started as f64 / 1000.0,
|
|
|
|
start: started as f64 / 1000.0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Some(division) => {
|
|
|
|
Some(division) => {
|
|
|
|
match division.matches.iter().find(|a| a.tuple == tuple) {
|
|
|
|
match division.matches.iter().find(|a| a.info.tuple == tuple) {
|
|
|
|
None => match_state = MatchState{
|
|
|
|
None => match_state = MatchState{
|
|
|
|
state: GameState::Scheduled,
|
|
|
|
state: GameState::Scheduled,
|
|
|
|
start: started as f64 / 1000.0,
|
|
|
|
start: started as f64 / 1000.0,
|
|
|
@ -261,12 +261,12 @@ impl Event {
|
|
|
|
match_list.push(Match{
|
|
|
|
match_list.push(Match{
|
|
|
|
state: match_state,
|
|
|
|
state: match_state,
|
|
|
|
info: MatchInfo{
|
|
|
|
info: MatchInfo{
|
|
|
|
|
|
|
|
tuple: tuple.clone(),
|
|
|
|
red_teams: [String::from(red_1), String::from(red_2)],
|
|
|
|
red_teams: [String::from(red_1), String::from(red_2)],
|
|
|
|
blue_teams: [String::from(blue_1), String::from(blue_2)],
|
|
|
|
blue_teams: [String::from(blue_1), String::from(blue_2)],
|
|
|
|
field,
|
|
|
|
field,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
score: None,
|
|
|
|
score: None,
|
|
|
|
tuple: tuple.clone(),
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
None => {
|
|
|
@ -274,12 +274,12 @@ impl Event {
|
|
|
|
new_match_list.push(Match{
|
|
|
|
new_match_list.push(Match{
|
|
|
|
state: match_state,
|
|
|
|
state: match_state,
|
|
|
|
info: MatchInfo{
|
|
|
|
info: MatchInfo{
|
|
|
|
|
|
|
|
tuple: tuple.clone(),
|
|
|
|
red_teams: [String::from(red_1), String::from(red_2)],
|
|
|
|
red_teams: [String::from(red_1), String::from(red_2)],
|
|
|
|
blue_teams: [String::from(blue_1), String::from(blue_2)],
|
|
|
|
blue_teams: [String::from(blue_1), String::from(blue_2)],
|
|
|
|
field,
|
|
|
|
field,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
score: None,
|
|
|
|
score: None,
|
|
|
|
tuple: tuple.clone(),
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
matches.insert(tuple.division, new_match_list);
|
|
|
|
matches.insert(tuple.division, new_match_list);
|
|
|
|
},
|
|
|
|
},
|
|
|
@ -327,6 +327,7 @@ struct MatchState {
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
struct MatchInfo {
|
|
|
|
struct MatchInfo {
|
|
|
|
|
|
|
|
tuple: MatchTuple,
|
|
|
|
red_teams: [String; 2],
|
|
|
|
red_teams: [String; 2],
|
|
|
|
blue_teams: [String; 2],
|
|
|
|
blue_teams: [String; 2],
|
|
|
|
field: FieldTuple,
|
|
|
|
field: FieldTuple,
|
|
|
@ -337,7 +338,6 @@ struct Match {
|
|
|
|
state: MatchState,
|
|
|
|
state: MatchState,
|
|
|
|
info: MatchInfo,
|
|
|
|
info: MatchInfo,
|
|
|
|
score: Option<MatchScore>,
|
|
|
|
score: Option<MatchScore>,
|
|
|
|
tuple: MatchTuple,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
@ -920,7 +920,7 @@ fn on_score_set(notice: tm::Notice, event: &mut Event, _connection: &mut TMConne
|
|
|
|
let Some(scores) = notice.match_score else { return Vec::new() };
|
|
|
|
let Some(scores) = notice.match_score else { return Vec::new() };
|
|
|
|
let Some(score) = get_game_score(&scores) else { return Vec::new() };
|
|
|
|
let Some(score) = get_game_score(&scores) else { return Vec::new() };
|
|
|
|
let Some(division) = &mut event.divisions.get_mut(&tuple.division) else { return Vec::new() };
|
|
|
|
let Some(division) = &mut event.divisions.get_mut(&tuple.division) else { return Vec::new() };
|
|
|
|
let Some(m) = &mut division.matches.iter_mut().find(|a| a.tuple == tuple) else { return Vec::new() };
|
|
|
|
let Some(m) = &mut division.matches.iter_mut().find(|a| a.info.tuple == tuple) else { return Vec::new() };
|
|
|
|
|
|
|
|
|
|
|
|
m.score = Some(score.clone());
|
|
|
|
m.score = Some(score.clone());
|
|
|
|
m.state = MatchState{
|
|
|
|
m.state = MatchState{
|
|
|
@ -930,33 +930,29 @@ fn on_score_set(notice: tm::Notice, event: &mut Event, _connection: &mut TMConne
|
|
|
|
|
|
|
|
|
|
|
|
let score_serialized = serde_json::to_string_pretty(&m.score).unwrap();
|
|
|
|
let score_serialized = serde_json::to_string_pretty(&m.score).unwrap();
|
|
|
|
let state_serialized = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
let state_serialized = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
let game_score_topic = format!("division/{}/{:?}/{}/score", tuple.division, tuple.round, tuple.match_num);
|
|
|
|
|
|
|
|
let game_state_topic = format!("division/{}/{:?}/{}/state", tuple.division, tuple.round, tuple.match_num);
|
|
|
|
|
|
|
|
let mut out = Vec::new();
|
|
|
|
let mut out = Vec::new();
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
topic: game_score_topic,
|
|
|
|
topic: tuple.topic("/score"),
|
|
|
|
payload: score_serialized.clone(),
|
|
|
|
payload: score_serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
topic: game_state_topic,
|
|
|
|
topic: tuple.topic("/state"),
|
|
|
|
payload: state_serialized.clone(),
|
|
|
|
payload: state_serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
for (field_set_id, field_set) in &event.field_sets {
|
|
|
|
for (_, field_set) in &event.field_sets {
|
|
|
|
for (field_id, field) in &field_set.fields {
|
|
|
|
for (_, field) in &field_set.fields {
|
|
|
|
match field.last_known_match {
|
|
|
|
match field.last_known_match {
|
|
|
|
None => {},
|
|
|
|
None => {},
|
|
|
|
Some(last_known_match) => {
|
|
|
|
Some(last_known_match) => {
|
|
|
|
if last_known_match == tuple {
|
|
|
|
if last_known_match == tuple {
|
|
|
|
let field_score_topic = format!("field/{}/{}/score", field_set_id, field_id);
|
|
|
|
|
|
|
|
let field_state_topic = format!("field/{}/{}/state", field_set_id, field_id);
|
|
|
|
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
topic: field_score_topic,
|
|
|
|
topic: field.tuple.topic("/score"),
|
|
|
|
payload: score_serialized.clone(),
|
|
|
|
payload: score_serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
topic: field_state_topic,
|
|
|
|
topic: field.tuple.topic("/state"),
|
|
|
|
payload: state_serialized.clone(),
|
|
|
|
payload: state_serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -972,26 +968,24 @@ fn on_score_change(notice: tm::Notice, event: &mut Event, _connection: &mut TMCo
|
|
|
|
let Some(scores) = notice.match_score else { return Vec::new() };
|
|
|
|
let Some(scores) = notice.match_score else { return Vec::new() };
|
|
|
|
let Some(score) = get_game_score(&scores) else { return Vec::new() };
|
|
|
|
let Some(score) = get_game_score(&scores) else { return Vec::new() };
|
|
|
|
let Some(division) = &mut event.divisions.get_mut(&tuple.division) else { return Vec::new() };
|
|
|
|
let Some(division) = &mut event.divisions.get_mut(&tuple.division) else { return Vec::new() };
|
|
|
|
let Some(m) = &mut division.matches.iter_mut().find(|a| a.tuple == tuple) else { return Vec::new() };
|
|
|
|
let Some(m) = &mut division.matches.iter_mut().find(|a| a.info.tuple == tuple) else { return Vec::new() };
|
|
|
|
|
|
|
|
|
|
|
|
m.score = Some(score.clone());
|
|
|
|
m.score = Some(score.clone());
|
|
|
|
|
|
|
|
|
|
|
|
let serialized = serde_json::to_string_pretty(&score).unwrap();
|
|
|
|
let serialized = serde_json::to_string_pretty(&score).unwrap();
|
|
|
|
let game_topic = format!("division/{}/{:?}/{}/score", tuple.division, tuple.round, tuple.match_num);
|
|
|
|
|
|
|
|
let mut out = Vec::new();
|
|
|
|
let mut out = Vec::new();
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
topic: game_topic,
|
|
|
|
topic: tuple.topic("/score"),
|
|
|
|
payload: serialized.clone(),
|
|
|
|
payload: serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
for (field_set_id, field_set) in &event.field_sets {
|
|
|
|
for (_, field_set) in &event.field_sets {
|
|
|
|
for (field_id, field) in &field_set.fields {
|
|
|
|
for (_, field) in &field_set.fields {
|
|
|
|
match field.last_known_match {
|
|
|
|
match field.last_known_match {
|
|
|
|
None => {},
|
|
|
|
None => {},
|
|
|
|
Some(last_known_match) => {
|
|
|
|
Some(last_known_match) => {
|
|
|
|
if last_known_match == tuple {
|
|
|
|
if last_known_match == tuple {
|
|
|
|
let field_topic = format!("field/{}/{}/score", field_set_id, field_id);
|
|
|
|
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
out.push(MQTTMessage{
|
|
|
|
topic: field_topic,
|
|
|
|
topic: field.tuple.topic("/score"),
|
|
|
|
payload: serialized.clone(),
|
|
|
|
payload: serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1017,13 +1011,41 @@ fn on_match_list_update(_notice: tm::Notice, event: &mut Event, connection: &mut
|
|
|
|
for m in &division.matches {
|
|
|
|
for m in &division.matches {
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
topic: m.tuple.topic(""),
|
|
|
|
topic: m.info.tuple.topic(""),
|
|
|
|
payload: serialized
|
|
|
|
payload: serialized
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let serialized_state = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
|
|
|
|
topic: m.info.tuple.topic("/state"),
|
|
|
|
|
|
|
|
payload: serialized_state,
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (_, field_set) in &event.field_sets {
|
|
|
|
|
|
|
|
for (_, field) in &field_set.fields {
|
|
|
|
|
|
|
|
match field.last_known_match {
|
|
|
|
|
|
|
|
None => {},
|
|
|
|
|
|
|
|
Some(tuple) => {
|
|
|
|
|
|
|
|
let Some(m) = get_match(&mut event.divisions, tuple) else {continue;};
|
|
|
|
|
|
|
|
let serialized_state = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
|
|
|
|
topic: field.tuple.topic(""),
|
|
|
|
|
|
|
|
payload: serialized,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
|
|
|
|
topic: field.tuple.topic("/state"),
|
|
|
|
|
|
|
|
payload: serialized_state,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return messages;
|
|
|
|
return messages;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1048,23 +1070,26 @@ fn on_field_assigned(notice: tm::Notice, event: &mut Event, _connection: &mut TM
|
|
|
|
let mut messages = Vec::new();
|
|
|
|
let mut messages = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
let field_topic = field_info.topic("/state");
|
|
|
|
let serialized_info = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
let match_topic = tuple.topic("/state");
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
topic: field_topic,
|
|
|
|
topic: field_info.topic("/state"),
|
|
|
|
payload: serialized.clone(),
|
|
|
|
payload: serialized.clone(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
topic: match_topic,
|
|
|
|
topic: field_info.topic(""),
|
|
|
|
|
|
|
|
payload: serialized_info,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
|
|
|
|
topic: tuple.topic("/state"),
|
|
|
|
payload: serialized,
|
|
|
|
payload: serialized,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(score) = &m.score {
|
|
|
|
if let Some(score) = &m.score {
|
|
|
|
let serialized = serde_json::to_string_pretty(&score).unwrap();
|
|
|
|
let serialized = serde_json::to_string_pretty(&score).unwrap();
|
|
|
|
let topic = tuple.topic("/score");
|
|
|
|
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
messages.push(MQTTMessage{
|
|
|
|
topic,
|
|
|
|
topic: tuple.topic("/score"),
|
|
|
|
payload: serialized,
|
|
|
|
payload: serialized,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1245,14 +1270,14 @@ fn main() {
|
|
|
|
for (_, division) in &mut event.divisions {
|
|
|
|
for (_, division) in &mut event.divisions {
|
|
|
|
for m in &mut division.matches {
|
|
|
|
for m in &mut division.matches {
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
client.publish(m.tuple.topic(""), QoS::AtLeastOnce, true, serialized).unwrap();
|
|
|
|
client.publish(m.info.tuple.topic(""), QoS::AtLeastOnce, true, serialized).unwrap();
|
|
|
|
m.score = get_match_score(&tm_connection, struct_tuple_to_tm(m.tuple));
|
|
|
|
m.score = get_match_score(&tm_connection, struct_tuple_to_tm(m.info.tuple));
|
|
|
|
|
|
|
|
|
|
|
|
let state_serialized = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
let state_serialized = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
client.publish(m.tuple.topic("/state"), QoS::AtLeastOnce, true, state_serialized).unwrap();
|
|
|
|
client.publish(m.info.tuple.topic("/state"), QoS::AtLeastOnce, true, state_serialized).unwrap();
|
|
|
|
if let Some(score) = &m.score {
|
|
|
|
if let Some(score) = &m.score {
|
|
|
|
let serialized_score = serde_json::to_string_pretty(score).unwrap();
|
|
|
|
let serialized_score = serde_json::to_string_pretty(score).unwrap();
|
|
|
|
client.publish(m.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).unwrap();
|
|
|
|
client.publish(m.info.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1280,6 +1305,8 @@ fn main() {
|
|
|
|
None => {},
|
|
|
|
None => {},
|
|
|
|
Some(field) => {
|
|
|
|
Some(field) => {
|
|
|
|
field.last_known_match = Some(tuple);
|
|
|
|
field.last_known_match = Some(tuple);
|
|
|
|
|
|
|
|
let serialized = serde_json::to_string_pretty(&m.info).unwrap();
|
|
|
|
|
|
|
|
client.publish(field.tuple.topic(""), QoS::AtLeastOnce, true, serialized).unwrap();
|
|
|
|
let serialized_score = serde_json::to_string_pretty(&m.score).unwrap();
|
|
|
|
let serialized_score = serde_json::to_string_pretty(&m.score).unwrap();
|
|
|
|
client.publish(field.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).unwrap();
|
|
|
|
client.publish(field.tuple.topic("/score"), QoS::AtLeastOnce, true, serialized_score).unwrap();
|
|
|
|
let serialized_state = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
|
let serialized_state = serde_json::to_string_pretty(&m.state).unwrap();
|
|
|
@ -1324,11 +1351,9 @@ fn main() {
|
|
|
|
None => log::warn!("Received state change for unknown match {:#?}", state_change.tuple),
|
|
|
|
None => log::warn!("Received state change for unknown match {:#?}", state_change.tuple),
|
|
|
|
Some(m) => {
|
|
|
|
Some(m) => {
|
|
|
|
m.state = state_change.next_state.clone();
|
|
|
|
m.state = state_change.next_state.clone();
|
|
|
|
let field_state_topic = format!("field/{}/{}/state", state_change.field.set, state_change.field.id);
|
|
|
|
let state_serialized = serde_json::to_vec_pretty(&state_change.next_state).unwrap();
|
|
|
|
let match_state_topic = format!("division/{}/{:?}/{}/score", state_change.tuple.division, state_change.tuple.round, state_change.tuple.match_num);
|
|
|
|
client.publish(state_change.field.topic("/state"), QoS::AtLeastOnce, true, state_serialized.clone()).expect("Failed MQTT publish");
|
|
|
|
let payload = serde_json::to_vec_pretty(&state_change.next_state).unwrap();
|
|
|
|
client.publish(m.info.tuple.topic("/state"), QoS::AtLeastOnce, true, state_serialized).expect("Failed MQTT publish");
|
|
|
|
client.publish(field_state_topic, QoS::AtLeastOnce, true, payload.clone()).expect("Failed MQTT publish");
|
|
|
|
|
|
|
|
client.publish(match_state_topic, QoS::AtLeastOnce, true, payload).expect("Failed MQTT publish");
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|