summaryrefslogtreecommitdiff
path: root/scarymaze/src/client.rs
diff options
context:
space:
mode:
authorJakob L. Kreuze <zerodaysfordays@sdf.org>2021-04-06 12:23:00 -0400
committerJakob L. Kreuze <zerodaysfordays@sdf.org>2021-04-06 12:25:17 -0400
commit983cd29f5a2c3d9cd1d6a9c4f343adcffe54f88c (patch)
tree395f4bf2dfe097d9d09413ad1b805765b2e7eae0 /scarymaze/src/client.rs
Initial import.HEADmaster
Diffstat (limited to 'scarymaze/src/client.rs')
-rw-r--r--scarymaze/src/client.rs350
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(())
+}