#[link(name = "openssl", kind = "static")] extern crate openssl; use maze_generator::ellers_algorithm::EllersGenerator; use maze_generator::prelude::*; // use petgraph::graphmap::GraphMap; // use std::cell::RefCell; // use std::rc::Rc; extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::pixels::Color; use sdl2::rect::Point; use std::f64::consts::PI; const WIDTH: i32 = 800; const HEIGHT: i32 = 600; struct Vec2 { x: T, y: T, } impl Vec2 { fn new(x: T, y: T) -> Vec2 { Vec2 { x, y } } } use std::io::prelude::*; use std::net::TcpStream; const HOST_NAME: &'static str = "scarymaze.dynamic.ctf.umasscybersec.org:8080"; const SERVER_MAP: u8 = 0; const SERVER_GOTO: u8 = 1; const SERVER_MESSAGE: u8 = 2; enum ClientMessage { North, South, East, West, Unknown, } const AES_KEY: &'static str = "STRINGS NOT HERE"; use openssl::symm::{decrypt, encrypt, Cipher}; use rand::RngCore; fn my_encrypt(packet: &[u8]) -> Vec { let mut rng = rand::thread_rng(); let mut iv = [0 as u8; 16]; rng.fill_bytes(&mut iv); let cipher = Cipher::aes_128_cbc(); let key = AES_KEY.as_bytes(); let mut data = encrypt(cipher, key, Some(&iv), packet).unwrap(); let mut ciphertext = Vec::from(iv); ciphertext.append(&mut data); ciphertext } fn my_decrypt(packet: &[u8]) -> Vec { let iv = &packet[..16]; let data = &packet[16..]; let cipher = Cipher::aes_128_cbc(); let key = AES_KEY.as_bytes(); let plaintext = decrypt(cipher, key, Some(iv), data).unwrap(); plaintext } fn print_map(map: &Vec>, pos: &Vec2) { let maze_size = 24; for y in 0..maze_size { for x in 0..maze_size { if x == pos.x && y == pos.y { print!("o"); } else if map[x as usize][y as usize] != 0 { if map[x as usize][y as usize] == 2 { print!("g"); } else { print!("x"); } } else { print!(" "); } } println!(); } } use std::convert::TryInto; use std::iter; fn update_server(stream: &mut TcpStream, message: ClientMessage) { let mut packet = Vec::new(); packet.push(match message { ClientMessage::North => 1, ClientMessage::East => 2, ClientMessage::West => 3, ClientMessage::South => 4, _ => 5, }); let mut ciphertext = my_encrypt(&packet); let mut packet = Vec::from((ciphertext.len() as u64).to_be_bytes()); packet.append(&mut ciphertext); stream.write(&packet); } fn main() -> Result<(), String> { let sdl_context = sdl2::init()?; let video_subsystem = sdl_context.video()?; let window = video_subsystem .window("scarymaze", WIDTH as u32, HEIGHT as u32) .position_centered() .build() .map_err(|e| e.to_string())?; let mut canvas = window .into_canvas() .software() .build() .map_err(|e| e.to_string())?; // Connect to server let mut buf = [0 as u8; 2048]; let mut stream = if let Ok(conn) = TcpStream::connect(HOST_NAME) { conn } else { println!("Couldn't connect to server."); return Err("Couldn't connect to server.".into()); }; stream.set_nonblocking(true); // Generate maze. let maze_size: usize = 24; let mut map = vec![vec![0; maze_size]; maze_size]; let mut generator = EllersGenerator::new(None); let maze = generator.generate((maze_size / 3) as i32, (maze_size / 3) as i32); for x in 0..maze_size { for y in 0..maze_size { if x == 0 || x == maze_size - 1 || y == 0 || y == maze_size - 1 { map[y][x] = 1; } } } let mut pos = Vec2::::new(22.5, 12.5); let mut dir = Vec2::::new(-1.0, 0.0); let mut plane = Vec2::::new(0.0, 0.66); 'mainloop: loop { // Check for updates from the server. if let Ok(n) = stream.peek(&mut buf) { let encrypted_length = u64::from_be_bytes((&buf[..8]).try_into().unwrap()) as usize; stream.read_exact( &mut iter::repeat(0) .take(8 + encrypted_length) .collect::>(), ); let packet = my_decrypt(&buf[8..8 + encrypted_length]); match packet[0] { SERVER_MAP => { for x in 0..maze_size { for y in 0..maze_size { map[y][x] = packet[1 + y * maze_size + x]; } } } SERVER_GOTO => { let x = i32::from_be_bytes((&packet[1..5]).try_into().unwrap()); let y = i32::from_be_bytes((&packet[5..]).try_into().unwrap()); pos = Vec2::::new(x as f64 + 0.5, y as f64 + 0.5); // print_map(&map, &Vec2::::new(pos.x as i32, pos.y as i32)); } SERVER_MESSAGE => { println!("{:?}", String::from_utf8_lossy(&packet[1..])); } _ => { println!("Received corrupted packet from server :("); } } } // Check for events. for event in sdl_context.event_pump()?.poll_iter() { match event { Event::KeyDown { keycode: Some(Keycode::Escape), .. } | Event::Quit { .. } => break 'mainloop, Event::KeyDown { keycode: Some(Keycode::Up), repeat: false, .. } => update_server( &mut stream, match (dir.x as i32, dir.y as i32) { (-1, 0) => ClientMessage::West, (0, -1) => ClientMessage::South, (1, 0) => ClientMessage::East, (0, 1) => ClientMessage::North, _ => ClientMessage::Unknown, }, ), Event::KeyDown { keycode: Some(Keycode::Down), repeat: false, .. } => update_server( &mut stream, match (dir.x as i32, dir.y as i32) { (-1, 0) => ClientMessage::East, (0, -1) => ClientMessage::North, (1, 0) => ClientMessage::West, (0, 1) => ClientMessage::South, _ => ClientMessage::Unknown, }, ), Event::KeyDown { keycode: Some(Keycode::Left), repeat: false, .. } => { let old_x = dir.x; dir.x = dir.x * f64::cos(PI / 2.0) - dir.y * f64::sin(PI / 2.0); dir.y = old_x * f64::sin(PI / 2.0) + dir.y * f64::cos(PI / 2.0); let old_plane_x = plane.x; plane.x = plane.x * f64::cos(PI / 2.0) - plane.y * f64::sin(PI / 2.0); plane.y = old_plane_x * f64::sin(PI / 2.0) + plane.y * f64::cos(PI / 2.0); } Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => { let old_x = dir.x; dir.x = dir.x * f64::cos(-PI / 2.0) - dir.y * f64::sin(-PI / 2.0); dir.y = old_x * f64::sin(-PI / 2.0) + dir.y * f64::cos(-PI / 2.0); let old_plane_x = plane.x; plane.x = plane.x * f64::cos(-PI / 2.0) - plane.y * f64::sin(-PI / 2.0); plane.y = old_plane_x * f64::sin(-PI / 2.0) + plane.y * f64::cos(-PI / 2.0); } _ => {} } } canvas.set_draw_color(Color::RGBA(0, 0, 0, 255)); canvas.clear(); for x in 0..WIDTH { // Calculate ray position and direction. let scan_dist = ((2 * x) as f64) / (WIDTH as f64) - 1.0; let ray_dir = Vec2::::new(dir.x + plane.x * scan_dist, dir.y + plane.y * scan_dist); // Which box of the map we're in. let mut map_pos = Vec2::::new(pos.x as i32, pos.y as i32); //length of ray from one x or y-side to next x or y-side let delta_dist = Vec2::::new((1.0 / ray_dir.x).abs(), (1.0 / ray_dir.y).abs()); let mut hit = false; // Was there a wall hit? let mut goal = false; let mut side = 0; // Was a north/south or a east/west wall hit? // Calculate step and initial sideDist. let (step_x, mut side_dist_x) = if ray_dir.x < 0.0 { (-1, (pos.x - map_pos.x as f64) * delta_dist.x) } else { (1, ((map_pos.x as f64) + 1.0 - pos.x) * delta_dist.x) }; let (step_y, mut side_dist_y) = if ray_dir.y < 0.0 { (-1, (pos.y - map_pos.y as f64) * delta_dist.y) } else { (1, ((map_pos.y as f64) + 1.0 - pos.y) * delta_dist.y) }; // Perform Digital Differential Analysis. while !hit { // Jump to next map square, OR in x-direction, OR in y-direction. if side_dist_x < side_dist_y { side_dist_x += delta_dist.x; map_pos.x += step_x; side = 0; } else { side_dist_y += delta_dist.y; map_pos.y += step_y; side = 1; } // Check if ray has hit a wall. if map[map_pos.x as usize][map_pos.y as usize] > 0 { hit = true; if map[map_pos.x as usize][map_pos.y as usize] > 1 { goal = true; } } } // Calculate distance projected on camera direction (Euclidean distance will give fisheye effect!) let perp_wall_dist = if side == 0 { ((map_pos.x as f64 - pos.x) + (1.0 - step_x as f64) / 2.0) / ray_dir.x } else { ((map_pos.y as f64 - pos.y) + (1.0 - step_y as f64) / 2.0) / ray_dir.y }; // Calculate height of line to draw on screen let line_height = if perp_wall_dist > 0.0 { (HEIGHT as f64 / perp_wall_dist) as i32 } else { HEIGHT }; // Calculate lowest and highest pixel to fill in current stripe. let draw_start = -line_height / 2 + HEIGHT / 2; let draw_end = line_height / 2 + HEIGHT / 2; // Draw the pixels of the stripe as a vertical line. let start = Point::new(x, draw_start); let end = Point::new(x, draw_end); if goal { canvas.set_draw_color(Color::RGBA( (255 * line_height / HEIGHT) as u8, (255 * line_height / HEIGHT) as u8, 0, 255, )); } else { canvas.set_draw_color(Color::RGBA(0, (255 * line_height / HEIGHT) as u8, 0, 255)); } canvas.draw_line(start, end).unwrap(); } canvas.present(); } Ok(()) }