2025-12-14 22:04:04 +00:00
|
|
|
use macroquad::prelude as mq;
|
2026-02-23 08:23:52 +00:00
|
|
|
use std::fs::File;
|
|
|
|
|
use std::io::{Read, Write};
|
2025-12-14 22:04:04 +00:00
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
#[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
2025-12-14 22:04:04 +00:00
|
|
|
pub struct JoystickInput {
|
|
|
|
|
pub throttle_input: f32,
|
2026-02-06 18:35:23 +00:00
|
|
|
pub roll_input: f32,
|
2025-12-14 22:04:04 +00:00
|
|
|
pub yaw_input: f32,
|
|
|
|
|
pub pitch_input: f32,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
#[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct PositionInput {
|
|
|
|
|
pub lat: f32,
|
|
|
|
|
pub long: f32,
|
|
|
|
|
pub alt: f32,
|
|
|
|
|
}
|
2025-12-14 22:04:04 +00:00
|
|
|
|
2026-03-02 16:09:30 +00:00
|
|
|
#[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct AccelerationInput {
|
|
|
|
|
pub x: f32,
|
|
|
|
|
pub y: f32,
|
|
|
|
|
pub z: f32,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 12:31:52 +00:00
|
|
|
#[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct RotationInput {
|
|
|
|
|
pub roll: f32,
|
|
|
|
|
pub yaw: f32,
|
|
|
|
|
pub pitch: f32,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
#[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub enum ModeInput {
|
|
|
|
|
#[default]
|
|
|
|
|
Acro,
|
2026-03-02 15:39:21 +00:00
|
|
|
Rotation,
|
2026-03-02 16:09:30 +00:00
|
|
|
Acceleration,
|
2026-02-23 08:23:52 +00:00
|
|
|
Navigation,
|
2025-12-14 22:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
#[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct Input {
|
2026-03-02 18:40:33 +00:00
|
|
|
#[serde(default)]
|
2026-02-23 08:23:52 +00:00
|
|
|
pub joystick: JoystickInput,
|
2026-03-02 18:40:33 +00:00
|
|
|
#[serde(default)]
|
2026-03-02 16:09:30 +00:00
|
|
|
pub acceleration: AccelerationInput,
|
2026-03-02 18:40:33 +00:00
|
|
|
#[serde(default)]
|
2026-02-24 12:31:52 +00:00
|
|
|
pub rotation: RotationInput,
|
2026-03-02 18:40:33 +00:00
|
|
|
#[serde(default)]
|
2026-03-02 16:09:30 +00:00
|
|
|
pub position: PositionInput,
|
2026-02-23 08:23:52 +00:00
|
|
|
pub mode: ModeInput,
|
2025-12-14 22:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
#[derive(Default, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct InputRecord {
|
|
|
|
|
input: Input,
|
|
|
|
|
time: f32,
|
2025-12-14 22:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
|
2025-12-14 22:04:04 +00:00
|
|
|
pub struct InputRecording {
|
2026-02-23 08:23:52 +00:00
|
|
|
records: Vec<InputRecord>,
|
2025-12-14 22:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InputRecording {
|
2026-02-23 08:23:52 +00:00
|
|
|
pub fn save_to_file(&self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
|
|
|
|
let json = serde_json::to_string_pretty(self)?;
|
2025-12-14 22:04:04 +00:00
|
|
|
let mut file = File::create(path)?;
|
2026-02-23 08:23:52 +00:00
|
|
|
file.write_all(json.as_bytes())?;
|
2025-12-14 22:04:04 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
pub fn load_from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
|
|
|
|
let mut file = File::open(path)?;
|
|
|
|
|
let mut contents = String::new();
|
|
|
|
|
file.read_to_string(&mut contents)?;
|
|
|
|
|
let recording: Self = serde_json::from_str(&contents)?;
|
|
|
|
|
Ok(recording)
|
2025-12-14 22:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-23 08:23:52 +00:00
|
|
|
pub fn has_ended(&self, time: f32) -> bool {
|
|
|
|
|
return self.records.last().unwrap_or(&InputRecord::default()).time < time;
|
|
|
|
|
}
|
|
|
|
|
pub fn get_input(&self, time: f32) -> Input {
|
2025-12-14 22:04:04 +00:00
|
|
|
/*
|
|
|
|
|
* Binary search returns index to element as OK, or where the element could be placed to
|
|
|
|
|
* keep order as Err, so if result is Ok return that input, if its Err, return the previous
|
|
|
|
|
* input if it exists, if it doesn't (because time is before the first action in the
|
|
|
|
|
* recorded sequence, return an empty input)
|
|
|
|
|
*/
|
|
|
|
|
let res = self
|
2026-02-23 08:23:52 +00:00
|
|
|
.records
|
|
|
|
|
.binary_search_by(|probe| probe.time.total_cmp(&time));
|
2025-12-14 22:04:04 +00:00
|
|
|
match res {
|
|
|
|
|
Ok(res) => {
|
|
|
|
|
return self
|
2026-02-23 08:23:52 +00:00
|
|
|
.records
|
2025-12-14 22:04:04 +00:00
|
|
|
.get(res)
|
|
|
|
|
.unwrap_or(&InputRecord::default())
|
|
|
|
|
.input;
|
|
|
|
|
}
|
|
|
|
|
Err(mut res) => {
|
|
|
|
|
if res > 0 {
|
|
|
|
|
res -= 1;
|
|
|
|
|
}
|
|
|
|
|
return self
|
2026-02-23 08:23:52 +00:00
|
|
|
.records
|
2025-12-14 22:04:04 +00:00
|
|
|
.get(0.max(res))
|
|
|
|
|
.unwrap_or(&InputRecord::default())
|
|
|
|
|
.input;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Current time should always be larger thant the last input records time.
|
|
|
|
|
* This method is made for recording inputs in real time, not for retroactively adding
|
|
|
|
|
*
|
|
|
|
|
* Returns the addded Joystick Input
|
|
|
|
|
*/
|
2026-02-23 08:23:52 +00:00
|
|
|
pub fn add_input_from_keyboard(&mut self, current_time: f32) -> Input {
|
|
|
|
|
let input = Input {
|
|
|
|
|
joystick: JoystickInput::from_keyboard(),
|
|
|
|
|
mode: ModeInput::Acro,
|
2026-03-02 16:09:30 +00:00
|
|
|
..Default::default()
|
2026-02-23 08:23:52 +00:00
|
|
|
};
|
|
|
|
|
let last_input = self.records.last();
|
2025-12-14 22:04:04 +00:00
|
|
|
match last_input {
|
|
|
|
|
Some(last_record) => {
|
|
|
|
|
if last_record.input != input {
|
2026-02-23 08:23:52 +00:00
|
|
|
self.records.push(InputRecord {
|
2025-12-14 22:04:04 +00:00
|
|
|
input,
|
2026-02-23 08:23:52 +00:00
|
|
|
time: current_time,
|
2025-12-14 22:04:04 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
2026-02-23 08:23:52 +00:00
|
|
|
self.records.push(InputRecord {
|
2025-12-14 22:04:04 +00:00
|
|
|
input,
|
2026-02-23 08:23:52 +00:00
|
|
|
time: current_time,
|
2025-12-14 22:04:04 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-23 08:23:52 +00:00
|
|
|
|
|
|
|
|
impl JoystickInput {
|
|
|
|
|
pub fn from_keyboard() -> Self {
|
|
|
|
|
let mut input = Self::default();
|
|
|
|
|
if mq::is_key_down(mq::KeyCode::W) {
|
|
|
|
|
input.throttle_input = 1.0;
|
|
|
|
|
}
|
|
|
|
|
if mq::is_key_down(mq::KeyCode::S) {
|
|
|
|
|
input.throttle_input = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if mq::is_key_down(mq::KeyCode::A) {
|
|
|
|
|
input.yaw_input = 1.0;
|
|
|
|
|
} else if mq::is_key_down(mq::KeyCode::D) {
|
|
|
|
|
input.yaw_input = -1.0;
|
|
|
|
|
} else {
|
|
|
|
|
input.yaw_input = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if mq::is_key_down(mq::KeyCode::Up) {
|
|
|
|
|
input.pitch_input = -1.0;
|
|
|
|
|
} else if mq::is_key_down(mq::KeyCode::Down) {
|
|
|
|
|
input.pitch_input = 1.0;
|
|
|
|
|
} else {
|
|
|
|
|
input.pitch_input = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if mq::is_key_down(mq::KeyCode::Left) {
|
|
|
|
|
input.roll_input = -1.0;
|
|
|
|
|
} else if mq::is_key_down(mq::KeyCode::Right) {
|
|
|
|
|
input.roll_input = 1.0;
|
|
|
|
|
} else {
|
|
|
|
|
input.roll_input = 0.0;
|
|
|
|
|
}
|
|
|
|
|
input = input.clamp();
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
}
|