#![allow(unused)] use macroquad::prelude as mq; use serde::{Deserialize, Serialize}; use std::fs::File; use std::io::{Read, Write}; #[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] pub struct JoystickInput { pub throttle_input: f32, pub roll_input: f32, pub yaw_input: f32, pub pitch_input: f32, } #[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] pub struct PositionInput { pub lat: f32, pub long: f32, pub alt: f32, } #[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] pub struct AccelerationInput { pub x: f32, pub y: f32, pub z: f32, } #[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] pub struct RotationInput { pub roll: f32, pub yaw: f32, pub pitch: f32, } #[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] pub enum ModeInput { #[default] Acro, Rotation, Acceleration, Navigation, } #[derive(Default, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Input { pub joystick: JoystickInput, pub acceleration: AccelerationInput, pub rotation: RotationInput, pub position: PositionInput, pub mode: ModeInput, } #[derive(Default, Clone, Copy, serde::Serialize, serde::Deserialize)] pub struct InputRecord { input: Input, time: f32, } #[derive(Default, Clone, serde::Serialize, serde::Deserialize)] pub struct InputRecording { records: Vec, } impl InputRecording { pub fn save_to_file(&self, path: &str) -> Result<(), Box> { let json = serde_json::to_string_pretty(self)?; let mut file = File::create(path)?; file.write_all(json.as_bytes())?; Ok(()) } pub fn load_from_file(path: &str) -> Result> { 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) } 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 { /* * 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 .records .binary_search_by(|probe| probe.time.total_cmp(&time)); match res { Ok(res) => { return self .records .get(res) .unwrap_or(&InputRecord::default()) .input; } Err(mut res) => { if res > 0 { res -= 1; } return self .records .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 */ pub fn add_input_from_keyboard(&mut self, current_time: f32) -> Input { let input = Input { joystick: JoystickInput::from_keyboard(), mode: ModeInput::Acro, ..Default::default() }; let last_input = self.records.last(); match last_input { Some(last_record) => { if last_record.input != input { self.records.push(InputRecord { input, time: current_time, }); } } None => { self.records.push(InputRecord { input, time: current_time, }); } } return input; } } 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; } }