diff --git a/Cargo.lock b/Cargo.lock index 5dba0ea..c2bf58b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cfg-if" version = "1.0.0" @@ -41,7 +47,16 @@ checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", ] [[package]] @@ -56,6 +71,63 @@ version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -75,12 +147,75 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "ppv-lite86" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.8.5" @@ -111,6 +246,21 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "sdl2" version = "0.35.2" @@ -134,6 +284,42 @@ dependencies = [ "version-compare", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "time" version = "0.1.43" @@ -144,6 +330,43 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce653fb475565de9f6fb0614b28bca8df2c430c0cf84bcd9c843f15de5414cc" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + [[package]] name = "version-compare" version = "0.1.0" @@ -156,6 +379,12 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winapi" version = "0.3.9" @@ -178,6 +407,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "winelounge" version = "0.1.0" @@ -185,4 +457,5 @@ dependencies = [ "chrono", "rand", "sdl2", + "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index a0a66b6..1cc49c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "winelounge" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +autobins = true [dependencies] chrono = "0.4" @@ -13,6 +13,11 @@ rand = "0.8" version = "0.35" features = ["image", "ttf"] +[dependencies.tokio] +version = "1.18" +features = ["full"] +default-features = false + [profile.release] opt-level = "s" codegen-units = 1 diff --git a/src/bin/winelounge-server/main.rs b/src/bin/winelounge-server/main.rs new file mode 100644 index 0000000..b7b85ae --- /dev/null +++ b/src/bin/winelounge-server/main.rs @@ -0,0 +1,12 @@ +#[tokio::main] +async fn main() { + + let listener = tokio::net::TcpListener::bind(":7888").await.expect("Cannot open socket"); + + 'listener: loop { + + let (socket, _) = listener.accept().await.expect("Cannot accept connection"); + + } + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 7c07e66..e876218 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use crate::world::World; mod player; mod sprite; mod world; +mod net; const GLASS_SPACE: u8 = 5; @@ -40,6 +41,8 @@ fn main() { let mut world = World::init(); + world.spawn_player("Test".to_string(), 100, 100); + 'running: loop { for event in event_pump.poll_iter() { match event { diff --git a/src/net.rs b/src/net.rs new file mode 100644 index 0000000..081dc4b --- /dev/null +++ b/src/net.rs @@ -0,0 +1,183 @@ +use crate::world::{BoxAreaContent, BoxAreaPosition, Command, Direction}; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; + +impl Display for Direction { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Direction::Up => write!(f, "Up"), + Direction::Down => write!(f, "Down"), + Direction::Left => write!(f, "Left"), + Direction::Right => write!(f, "Right"), + } + } +} + +impl FromStr for Direction { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "Up" => Ok(Direction::Up), + "Down" => Ok(Direction::Down), + "Left" => Ok(Direction::Left), + "Right" => Ok(Direction::Right), + _ => Err(()), + } + } +} + +impl Display for BoxAreaPosition { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + BoxAreaPosition::RightTop => write!(f, "RightTop"), + BoxAreaPosition::RightBottom => write!(f, "RightBottom"), + BoxAreaPosition::LeftBottom => write!(f, "LeftBottom"), + BoxAreaPosition::LeftTop => write!(f, "LeftTop"), + } + } +} + +impl FromStr for BoxAreaPosition { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "RightTop" => Ok(BoxAreaPosition::RightTop), + "RightBottom" => Ok(BoxAreaPosition::RightBottom), + "LeftBottom" => Ok(BoxAreaPosition::LeftBottom), + "LeftTop" => Ok(BoxAreaPosition::LeftTop), + _ => Err(()), + } + } +} + +impl Display for BoxAreaContent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + BoxAreaContent::Nothing => write!(f, "Nothing"), + BoxAreaContent::HiddenBox => write!(f, "HiddenBox"), + BoxAreaContent::EmptyGlass => write!(f, "EmptyGlass"), + BoxAreaContent::FilledBottle => write!(f, "FilledBottle"), + BoxAreaContent::EmptyBottle => write!(f, "EmptyBottle"), + } + } +} + +impl FromStr for BoxAreaContent { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "Nothing" => Ok(BoxAreaContent::Nothing), + "HiddenBox" => Ok(BoxAreaContent::HiddenBox), + "EmptyGlass" => Ok(BoxAreaContent::EmptyGlass), + "FilledBottle" => Ok(BoxAreaContent::FilledBottle), + "EmptyBottle" => Ok(BoxAreaContent::EmptyBottle), + _ => Err(()), + } + } +} + +impl Display for Command { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Command::SpawnPlayer(player_id, x, y) => write!(f, "Spawn {}", player_id), + Command::RemovePlayer(player_id) => write!(f, "Face {}", player_id), + Command::FacePlayer(player_id, direction) => write!(f, "Face {} {}", player_id, direction), + Command::MovePlayer(player_id, direction) => write!(f, "Move {} {}", player_id, direction), + Command::StopPlayer(player_id) => write!(f, "Stop {}", player_id), + Command::UpdateBoxArea(pos, content) => write!(f, "UpdateBoxArea {} {}", pos, content), + } + } +} + +impl FromStr for Command { + type Err = (); + + fn from_str(s: &str) -> Result { + let mut parts = s.split(' '); + + match parts.next() { + Some("Spawn") => match parts.next() { + Some(player_id) => match parts.next() { + Some(x) => match parts.next() { + Some(y) => Ok(Command::SpawnPlayer(player_id.to_string(), x.parse().unwrap(), y.parse().unwrap())), + _ => Err(()) + }, + _ => Err(()) + } + _ => Err(()) + }, + Some("Remove") => match parts.next() { + Some(player_id) => Ok(Command::RemovePlayer(player_id.to_string())), + _ => Err(()) + }, + Some("Face") => match parts.next() { + Some(player_id) => match parts.next() { + Some(direction) => Ok(Command::FacePlayer(player_id.to_string(), direction.parse::().unwrap())), + _ => Err(()), + }, + _ => Err(()) + }, + Some("Move") => match parts.next() { + Some(player_id) => match parts.next() { + Some(direction) => Ok(Command::MovePlayer(player_id.to_string(), direction.parse::().unwrap())), + _ => Err(()), + }, + _ => Err(()) + }, + Some("Stop") => match parts.next() { + Some(player_id) => Ok(Command::StopPlayer(player_id.to_string())), + _ => Err(()) + }, + Some("UpdateBoxArea") => match parts.next() { + Some(position) => { + let position = position.parse::().unwrap(); + match parts.next() { + Some(content) => { + let content = content.parse::().unwrap(); + Ok(Command::UpdateBoxArea(position, content)) + } + _ => Err(()), + } + } + _ => Err(()), + }, + Some(_) | None => Err(()), + } + } +} + +#[cfg(test)] +mod test { + use crate::world::Direction::{Left, Up}; + use crate::world::{BoxAreaContent, BoxAreaPosition, Command}; + + #[test] + fn should_deserialize_command_line() { + assert_eq!( + Command::SpawnPlayer("1234".to_string(), 100, 200), + "Spawn 1234 100 200".parse::().unwrap() + ); + assert_eq!( + Command::RemovePlayer("1234".to_string()), + "Remove 1234".parse::().unwrap() + ); + assert_eq!( + Command::FacePlayer("1234".to_string(), Left), + "Face 1234 Left".parse::().unwrap() + ); + assert_eq!( + Command::MovePlayer("1234".to_string(), Up), + "Move 1234 Up".parse::().unwrap() + ); + assert_eq!(Command::StopPlayer("1234".to_string()), "Stop 1234".parse::().unwrap()); + assert_eq!( + Command::UpdateBoxArea(BoxAreaPosition::RightBottom, BoxAreaContent::HiddenBox), + "UpdateBoxArea RightBottom HiddenBox" + .parse::() + .unwrap() + ); + } +} diff --git a/src/player.rs b/src/player.rs index 64b1d37..8ad5df8 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,3 +1,4 @@ +use rand::random; use crate::sprite::Sprite; use crate::{sprite, GLASS_SPACE}; use sdl2::rect::{Point, Rect}; @@ -5,6 +6,7 @@ use sdl2::render::{Texture, WindowCanvas}; /// The player with his position, direction ... pub struct Player { + pub id: String, position: Point, direction: PlayerDirection, footstep: u8, @@ -24,8 +26,13 @@ enum PlayerDirection { impl Player { /// Initializes Player with fixed position and direction. pub fn init() -> Player { + Self::spawn(random::().to_string().as_str(), 380, 250) + } + + pub fn spawn(player_id: &str, x: u32, y: u32) -> Player { Player { - position: Point::new(380, 250), + id: player_id.to_string(), + position: Point::new(x as i32, y as i32), direction: PlayerDirection::Down, footstep: 0, empty_glasses: 0, diff --git a/src/world.rs b/src/world.rs index e447e45..aee499b 100644 --- a/src/world.rs +++ b/src/world.rs @@ -10,6 +10,7 @@ use crate::{Player, GLASS_SPACE}; pub struct World { player: Player, + remote_player: Option, right_top_box_area: BoxArea, right_bottom_box_area: BoxArea, left_bottom_box_area: BoxArea, @@ -23,6 +24,7 @@ impl World { pub fn init() -> World { World { player: Player::init(), + remote_player: None, right_top_box_area: BoxArea::new(BoxAreaPosition::RightTop, BoxAreaContent::EmptyGlass), right_bottom_box_area: BoxArea::new( BoxAreaPosition::RightBottom, @@ -43,6 +45,14 @@ impl World { } } + pub fn spawn_player(&mut self, player_id: String, x: u32, y: u32) { + self.remote_player = Some(Player::spawn(player_id.as_str(), x, y)); + } + + pub fn get_player(&mut self, _: String) -> &mut Player { + &mut self.player + } + pub fn playable_rect() -> Rect { Rect::new(0, 50, 800, 550) } @@ -52,58 +62,120 @@ impl World { /// This checks if player collides with any stop item or will move out of world. /// If player can move, move him and turn him to the correct side. pub fn handle_event(&mut self, event: Event) { + let player_id = self.player.id.clone(); match event { Event::KeyDown { keycode: Some(Keycode::Up) | Some(Keycode::W), .. } => { - self.player.move_up(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Up)); if self.collides_with_stop() || !self.player.within_rect(&Self::playable_rect()) { - self.player.move_down(); - self.player.face_up(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Down)); + self.execute_command(Command::FacePlayer(player_id.clone(), Direction::Up)); } } Event::KeyDown { keycode: Some(Keycode::Down) | Some(Keycode::S), .. } => { - self.player.move_down(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Down)); if self.collides_with_stop() || !self.player.within_rect(&Self::playable_rect()) { - self.player.move_up(); - self.player.face_down(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Up)); + self.execute_command(Command::FacePlayer(player_id.clone(), Direction::Down)); } } Event::KeyDown { keycode: Some(Keycode::Left) | Some(Keycode::A), .. } => { - self.player.move_left(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Left)); if self.collides_with_stop() || !self.player.within_rect(&Self::playable_rect()) { - self.player.move_right(); - self.player.face_left(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Right)); + self.execute_command(Command::FacePlayer(player_id.clone(), Direction::Left)); } } Event::KeyDown { keycode: Some(Keycode::Right) | Some(Keycode::D), .. } => { - self.player.move_right(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Right)); if self.collides_with_stop() || !self.player.within_rect(&Self::playable_rect()) { - self.player.move_left(); - self.player.face_right(); + self.execute_command(Command::MovePlayer(player_id.clone(), Direction::Left)); + self.execute_command(Command::FacePlayer(player_id.clone(), Direction::Right)); } } - Event::KeyUp { .. } => self.player.stop(), + Event::KeyUp { .. } => self.execute_command(Command::StopPlayer(player_id.clone())), _ => {} } } + /// Executes a command for world update. + pub fn execute_command(&mut self, command: Command) { + println!("{}", command); + + match command { + Command::SpawnPlayer(player_id, x, y) => &mut { + // TBD + }, + Command::RemovePlayer(player_id) => &mut { + // TBD + }, + Command::FacePlayer(player_id, Direction::Down) => { + &mut self.get_player(player_id).face_down() + }, + Command::FacePlayer(player_id, Direction::Up) => { + &mut self.get_player(player_id).face_up() + }, + Command::FacePlayer(player_id, Direction::Left) => { + &mut self.get_player(player_id).face_left() + }, + Command::FacePlayer(player_id, Direction::Right) => { + &mut self.get_player(player_id).face_right() + }, + Command::MovePlayer(player_id, Direction::Down) => { + &mut self.get_player(player_id).move_down() + }, + Command::MovePlayer(player_id, Direction::Up) => { + &mut self.get_player(player_id).move_up() + }, + Command::MovePlayer(player_id, Direction::Left) => { + &mut self.get_player(player_id).move_left() + }, + Command::MovePlayer(player_id, Direction::Right) => { + &mut self.get_player(player_id).move_right() + }, + Command::StopPlayer(player_id) => { + &mut self.get_player(player_id).stop() + }, + Command::UpdateBoxArea(position, content) => &mut { + match position { + BoxAreaPosition::RightTop => { + self.right_top_box_area.update_content(content); + self.right_top_box_area.last_update = chrono::Utc::now().timestamp(); + } + BoxAreaPosition::RightBottom => { + self.right_bottom_box_area.update_content(content); + self.right_top_box_area.last_update = chrono::Utc::now().timestamp(); + } + BoxAreaPosition::LeftBottom => { + self.left_bottom_box_area.update_content(content); + self.right_top_box_area.last_update = chrono::Utc::now().timestamp(); + } + BoxAreaPosition::LeftTop => { + self.left_top_box_area.update_content(content); + self.right_top_box_area.last_update = chrono::Utc::now().timestamp(); + } + }; + } + }; + } + /// Updates box areas to provide new boxes and remove items after some time pub fn update_box_areas(&mut self) { - World::update_box_area(&mut self.right_top_box_area); - World::update_box_area(&mut self.right_bottom_box_area); - World::update_box_area(&mut self.left_bottom_box_area); - World::update_box_area(&mut self.left_top_box_area); + self.update_box_area(BoxAreaPosition::RightTop); + self.update_box_area(BoxAreaPosition::RightBottom); + self.update_box_area(BoxAreaPosition::LeftBottom); + self.update_box_area(BoxAreaPosition::LeftTop); } /// Handles both, collisions with lounge and any box area @@ -159,6 +231,11 @@ impl World { // Player self.player.render(canvas, texture); + // Remote/other player + if let Some(remote_player) = &self.remote_player { + remote_player.render(canvas, texture); + } + // Points let x = font .render(format!("Score: {:#04}", self.player.points).as_str()) @@ -177,17 +254,28 @@ impl World { canvas.present(); } - fn update_box_area(box_area: &mut BoxArea) { + fn update_box_area(&mut self, box_area_position: BoxAreaPosition) { + let box_area = match box_area_position { + BoxAreaPosition::RightTop => &self.right_top_box_area, + BoxAreaPosition::RightBottom => &self.right_bottom_box_area, + BoxAreaPosition::LeftBottom => &self.left_bottom_box_area, + BoxAreaPosition::LeftTop => &self.left_top_box_area, + }; + let now = chrono::Utc::now().timestamp(); let r: i64 = (rand::random::() % 10) + 3; if box_area.content == BoxAreaContent::Nothing && box_area.last_update + 10 < now { - box_area.content = BoxAreaContent::HiddenBox; - box_area.last_update = now; + self.execute_command(Command::UpdateBoxArea( + box_area_position, + BoxAreaContent::HiddenBox, + )); } else if box_area.content != BoxAreaContent::Nothing && box_area.last_update + 30 < now - r { - box_area.content = BoxAreaContent::Nothing; - box_area.last_update = now; + self.execute_command(Command::UpdateBoxArea( + box_area_position, + BoxAreaContent::Nothing, + )); } } @@ -239,6 +327,7 @@ impl World { } } + // TODO Commands fn handle_boxarea_collisions(&mut self) { if let Collision::BoxArea(bap) = self.has_player_collision() { let ba = match bap { @@ -256,20 +345,38 @@ impl World { }; if content == BoxAreaContent::EmptyGlass && self.player.can_pick_glass() { - ba.update_content(BoxAreaContent::Nothing); + self.execute_command(Command::UpdateBoxArea(bap, BoxAreaContent::Nothing)); self.player.pick_glass(); } else if content == BoxAreaContent::EmptyGlass && !self.player.can_pick_glass() { - ba.update_content(BoxAreaContent::EmptyGlass); + self.execute_command(Command::UpdateBoxArea(bap, BoxAreaContent::EmptyGlass)); } else if content == BoxAreaContent::FilledBottle && self.player.can_fill_glass() { - ba.update_content(BoxAreaContent::EmptyBottle); + self.execute_command(Command::UpdateBoxArea(bap, BoxAreaContent::EmptyBottle)); self.player.fill_glass(); } else if content == BoxAreaContent::FilledBottle && !self.player.can_fill_glass() { - ba.update_content(BoxAreaContent::FilledBottle); + self.execute_command(Command::UpdateBoxArea(bap, BoxAreaContent::FilledBottle)); } } } } +#[derive(Debug, PartialEq)] +pub enum Direction { + Up, + Down, + Left, + Right, +} + +#[derive(Debug, PartialEq)] +pub enum Command { + SpawnPlayer(String, u32, u32), + RemovePlayer(String), + FacePlayer(String, Direction), + MovePlayer(String, Direction), + StopPlayer(String), + UpdateBoxArea(BoxAreaPosition, BoxAreaContent), +} + #[derive(Debug, PartialEq, Eq)] enum Collision { BoxArea(BoxAreaPosition), @@ -317,7 +424,7 @@ impl BoxArea { Rect::new(x_offset, y_offset, 110, 110) } - /// Checks if player collides with this BoxSrea + /// Checks if player collides with this BoxArea fn collides_with(&self, player: &Player) -> bool { self.bounding_rect().contains_point(player.center()) }