diff options
| author | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2021-04-06 12:23:00 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2021-04-06 12:25:17 -0400 |
| commit | 983cd29f5a2c3d9cd1d6a9c4f343adcffe54f88c (patch) | |
| tree | 395f4bf2dfe097d9d09413ad1b805765b2e7eae0 /scarymaze/src/client.rs | |
Diffstat (limited to 'scarymaze/src/client.rs')
| -rw-r--r-- | scarymaze/src/client.rs | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/scarymaze/src/client.rs b/scarymaze/src/client.rs new file mode 100644 index 0000000..fc31491 --- /dev/null +++ b/scarymaze/src/client.rs @@ -0,0 +1,350 @@ +#[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<T> { + x: T, + y: T, +} + +impl<T> Vec2<T> { + fn new(x: T, y: T) -> Vec2<T> { + 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<u8> { + 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<u8> { + 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<Vec<u8>>, pos: &Vec2<i32>) { + 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::<f64>::new(22.5, 12.5); + let mut dir = Vec2::<f64>::new(-1.0, 0.0); + let mut plane = Vec2::<f64>::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::<Vec<_>>(), + ); + 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::<f64>::new(x as f64 + 0.5, y as f64 + 0.5); + // print_map(&map, &Vec2::<i32>::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::<f64>::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::<i32>::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::<f64>::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(()) +} |