diff --git a/Cargo.lock b/Cargo.lock index f89e8c1..e1825ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -60,6 +70,7 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" name = "mcrizzledizzle" version = "0.1.0" dependencies = [ + "colored", "flate2", "lazy_static", "rand", @@ -115,3 +126,69 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index d017616..2b4c683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +colored = "2.1.0" flate2 = "1.0.30" lazy_static = "1.4.0" rand = "0.8.5" diff --git a/src/main.rs b/src/main.rs index de00923..c88be18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,13 @@ use std::io::prelude::*; -use std::net::{TcpListener, TcpStream}; -use std::ops::DerefMut; +use std::net::{SocketAddr, TcpListener, TcpStream}; use std::thread::sleep; use std::time::Duration; use std::thread; use std::sync::{Arc, Mutex}; -use std::sync::mpsc::{channel, Receiver}; use flate2::Compression; use flate2::write::GzEncoder; use rand::prelude::*; +use colored::Colorize; #[macro_use] extern crate lazy_static; @@ -46,6 +45,13 @@ enum SpecialPlayers { SelfPlayer = 0xFF } +#[derive(Copy, Clone, PartialEq)] +enum PlayerStatus { + Disconnected, + ConnectedSelf, + Connected +} + struct World { pub size_x: i16, pub size_y: i16, @@ -64,7 +70,7 @@ fn build_world(size_x: i16, size_y: i16, size_z: i16) -> Vec { if y == 0 { world_dat.push(rng.gen()); // Bookshelf } else { - world_dat.push(rng.gen::() % 0x31); // Air + world_dat.push(0x00); // Air } } } @@ -73,9 +79,9 @@ fn build_world(size_x: i16, size_y: i16, size_z: i16) -> Vec { return world_dat; } -const SIZE_X: i16 = 512; -const SIZE_Y: i16 = 128; -const SIZE_Z: i16 = 512; +const SIZE_X: i16 = 64; +const SIZE_Y: i16 = 32; +const SIZE_Z: i16 = 64; lazy_static!{ static ref WORLD: World = World { @@ -84,29 +90,34 @@ lazy_static!{ size_z: SIZE_Z, data: build_world(SIZE_X, SIZE_Y, SIZE_Z) }; - - static ref PLAYER_DB: [Arc>; 255] = core::array::from_fn(|_| Arc::new(Mutex::new(Player::default()))); } - -fn get_player(id: u8) -> Receiver { - let data = Arc::clone(&PLAYER_DB[id as usize]); - let (tx, rx) = channel::(); - let mut data = data.lock().unwrap(); - tx.send(data); - return rx; -} - -fn handle_client(mut stream: TcpStream, client_number: u8) { +fn handle_client(mut stream: TcpStream, client_number: u8, players_arc_clone: Arc>) { thread::spawn(move || { - let mut master_rot = 0; + let mut player_statuses = [PlayerStatus::Disconnected; 255]; + let mut immediate_join = [false; 255]; + { + let mut players = players_arc_clone.lock().unwrap(); + for i in 0..players.len() { + let current_player = &mut players[i]; + match current_player.id { + 255=> { + continue; + } + _=> { + player_statuses[i] = PlayerStatus::Connected; + immediate_join[i] = true; + //println!("Player {} is immediate join!", i); + } + } + } + } + player_statuses[client_number as usize] = PlayerStatus::ConnectedSelf; loop { let mut buffer = [0; 1]; let _ = stream.read(&mut buffer); - let mut current_player = &mut PLAYER_DB[client_number as usize]; - match buffer[0] { 0x00=> { let mut payload_buffer = [0; 130]; // Byte + String + String + Byte @@ -119,13 +130,13 @@ fn handle_client(mut stream: TcpStream, client_number: u8) { break; } - println!("Client Prot Ver: {}", payload_buffer[0]); + //println!("Client Prot Ver: {}", payload_buffer[0]); let mut username = String::new(); for i in 0..64 { username.push(payload_buffer[i+1] as char); } - println!("Username: {}", username); + //println!("Username: {}", username); let mut verif_key = [0; 64]; @@ -139,22 +150,43 @@ fn handle_client(mut stream: TcpStream, client_number: u8) { write!(&mut verif_key_formatted, "{:X}", byte).expect("Piss"); } - println!("Verification key: 0x{}", verif_key_formatted); + //println!("Verification key: 0x{}", verif_key_formatted); - println!("\"Unused\" Byte: {}", payload_buffer[129]); + //println!("\"Unused\" Byte: {}", payload_buffer[129]); - current_player.id = current_player; - current_player.username = username; - current_player.verification_key = verif_key; - current_player.unused = payload_buffer[129]; - current_player.position_x = 0; - current_player.position_y = 128; - current_player.position_z = 0; - current_player.yaw = 0; - current_player.pitch = 0; - current_player.operator = false; + { + let mut players = players_arc_clone.lock().unwrap(); + let current_player = &mut players[client_number as usize]; + + current_player.id = client_number; + current_player.username = username.trim().to_string(); + current_player.verification_key = verif_key; + current_player.unused = payload_buffer[129]; + current_player.position_x = 0; + current_player.position_y = 128; + current_player.position_z = 0; + current_player.yaw = 0; + current_player.pitch = 0; + current_player.operator = false; - bomb_server_details(&mut stream, current_player); + bomb_server_details(&mut stream, ¤t_player); + + for i in 0..immediate_join.len() { + if immediate_join[i] { + //println!("Immediately joining {}", i); + let _ = spawn_player( + &mut stream, + players[i].id, + &players[i].username, + players[i].position_x, + players[i].position_y, + players[i].position_z, + players[i].yaw, + players[i].pitch + ); + } + } + } }, 0x08=>{ let mut payload_buffer = [0; 9]; // SByte + FShort (2B) + FShort + FShort + @@ -165,13 +197,16 @@ fn handle_client(mut stream: TcpStream, client_number: u8) { let _ = client_disconnect(&mut stream, "Evil bit level hacking"); break; } + { + let mut players = players_arc_clone.lock().unwrap(); + let current_player = &mut players[client_number as usize]; + current_player.position_x = ((payload_buffer[1] as i16) << (8 as i16)) + payload_buffer[2] as i16; + current_player.position_y = ((payload_buffer[3] as i16) << (8 as i16)) + payload_buffer[4] as i16; + current_player.position_z = ((payload_buffer[5] as i16) << (8 as i16)) + payload_buffer[6] as i16; - current_player.position_x = ((payload_buffer[1] as i16) << (8 as i16)) + payload_buffer[2] as i16; - current_player.position_y = ((payload_buffer[3] as i16) << (8 as i16)) + payload_buffer[4] as i16; - current_player.position_z = ((payload_buffer[5] as i16) << (8 as i16)) + payload_buffer[6] as i16; - - current_player.yaw = payload_buffer[7]; - current_player.pitch = payload_buffer[8]; + current_player.yaw = payload_buffer[7]; + current_player.pitch = payload_buffer[8]; + } }, 0x0D=>{ let mut payload_buffer = [0; 65]; // Byte + String @@ -195,22 +230,56 @@ fn handle_client(mut stream: TcpStream, client_number: u8) { let is_kill = ping(&mut stream); // Ping that MF if is_kill.is_err() { - println!("Thread {} is kill!", client_number); break; } - for i in 0..254 { - let _ = orientation_update(&mut stream, i, (((i as u16 + master_rot as u16) % 255)) as u8, 0); + sleep(Duration::from_millis(50)); // 20 TPS TODO: Delta time + { + let players = players_arc_clone.lock().unwrap(); + for i in 0..players.len() { + if players[i].id != 255 { + if player_statuses[i] == PlayerStatus::Disconnected { + let _ = spawn_player( + &mut stream, + players[i].id, + &players[i].username, + players[i].position_x, + players[i].position_y, + players[i].position_z, + players[i].yaw, + players[i].pitch + ); + player_statuses[i] = PlayerStatus::Connected; + let _ = send_chat_message(&mut stream, players[i].id, format!("{} has joined the game!", &players[i].username)); + } + } else { + if player_statuses[i] == PlayerStatus::Connected { + let _ = despawn_player(&mut stream, i.try_into().unwrap()); + let _ = send_chat_message(&mut stream, i.try_into().unwrap(), format!("{} has left the game!", &players[i].username)); + player_statuses[i] = PlayerStatus::Disconnected; + } + } + if player_statuses[i] == PlayerStatus::Connected { + let _ = set_position_and_orientation( + &mut stream, + players[i].id, + players[i].position_x, + players[i].position_y, + players[i].position_z, + players[i].yaw, + players[i].pitch + ); + } + } } + } + { + let mut players = players_arc_clone.lock().unwrap(); + let current_player = &mut players[client_number as usize]; - if master_rot != 255 { - master_rot += 1; - } else { - master_rot = 0; - } - - sleep(Duration::from_millis(50)); + current_player.id = SpecialPlayers::SelfPlayer as u8; } + println!("Thread {} is kill!", client_number); }); } @@ -296,15 +365,22 @@ fn spawn_player(stream: &mut TcpStream, player_id: u8, name: &String, pos_x: i16 stream.write(&[player_id])?; stream_write_array(&to_mc_string(name), stream)?; - stream_write_short(pos_x << 5, stream)?; - stream_write_short(pos_y << 5, stream)?; - stream_write_short(pos_z << 5, stream)?; + stream_write_short(pos_x, stream)?; + stream_write_short(pos_y, stream)?; + stream_write_short(pos_z, stream)?; stream.write(&[yaw])?; stream.write(&[pitch])?; Ok(()) } +fn despawn_player(stream: &mut TcpStream, player_id: u8) -> std::io::Result<()> { + stream.write(&[0x0c])?; + stream.write(&[player_id])?; + + Ok(()) +} + fn send_chat_message(stream: &mut TcpStream, source_id: u8, message: String) -> std::io::Result<()> { stream.write(&[0x0D])?; @@ -314,13 +390,28 @@ fn send_chat_message(stream: &mut TcpStream, source_id: u8, message: String) -> Ok(()) } -fn orientation_update(stream: &mut TcpStream, player_id: u8, yaw: u8, pitch: u8) -> std::io::Result<()> { - stream.write(&[0x0B])?; +//fn orientation_update(stream: &mut TcpStream, player_id: u8, yaw: u8, pitch: u8) -> std::io::Result<()> { +// stream.write(&[0x0B])?; +// +// stream.write(&[player_id])?; +// stream.write(&[yaw])?; +// stream.write(&[pitch])?; +// +// Ok(()) +//} + +fn set_position_and_orientation(stream: &mut TcpStream, player_id: u8, pos_x: i16, pos_y: i16, pos_z: i16, yaw: u8, pitch: u8) -> std::io::Result<()> { + stream.write(&[0x08])?; stream.write(&[player_id])?; + + stream_write_short(pos_x, stream)?; + stream_write_short(pos_y, stream)?; + stream_write_short(pos_z, stream)?; + + stream.write(&[yaw])?; stream.write(&[pitch])?; - Ok(()) } @@ -388,39 +479,62 @@ fn send_level_data(stream: &mut TcpStream) -> std::io::Result<()> { } fn bomb_server_details(stream: &mut TcpStream, current_player: &Player) { - println!("Server IDENT"); + //println!("Server IDENT"); let _ = server_identification(stream, current_player.operator); - println!("Intialize level"); + //println!("Intialize level"); let _ = init_level(stream); - println!("Send level data"); + //println!("Send level data"); let _ = send_level_data(stream); // Approaching Nirvana - Maw of the beast - println!("Finalize level"); + //println!("Finalize level"); let _ = finalize_level(stream, WORLD.size_x, WORLD.size_y, WORLD.size_z); - println!("Spawning player"); - + //println!("Spawning player"); let _ = spawn_player(stream, SpecialPlayers::SelfPlayer as u8, ¤t_player.username, 64, 2, 64, 0, 0); +} - println!("Ping 3 times (idfk why we do this)"); - let _ = ping(stream); - let _ = ping(stream); - let _ = ping(stream); +fn _create_player_info_window(client_number: u8, players_arc_clone: Arc>) { + thread::spawn(move || { + let mut thread_alive = false; + loop { + { + let mut players = players_arc_clone.lock().unwrap(); + let current_player = &mut players[client_number as usize]; - for i in 0..254 { - let _ = spawn_player(stream, i, &format!("Test {}", i), (i % 15).into(), 2, (i / 17).into(), i, 0); - } + if current_player.id == 255 && thread_alive == true { + println!("[{}{}] {} has disconnected!", "THREAD: ".cyan(), client_number, current_player.username); + break; + } else { + thread_alive = true; + } + + println!("[{}{}] id: {}", "THREAD: ".cyan(), client_number, current_player.id); + println!("[{}{}] pos_x: {}", "THREAD: ".cyan(), client_number, current_player.position_x >> 5); + println!("[{}{}] pos_y: {}", "THREAD: ".cyan(), client_number, current_player.position_y >> 5); + println!("[{}{}] pos_z: {}", "THREAD: ".cyan(), client_number, current_player.position_z >> 5); + } + sleep(Duration::from_millis(200)); + } + }); } fn main() -> std::io::Result<()> { - let listener = TcpListener::bind("127.0.01:25565")?; + let players: [Player; 255] = core::array::from_fn(|_| Player::default()); + let players_arc = Arc::new(Mutex::new(players)); + + let addr = SocketAddr::from(([0, 0, 0, 0], 25565)); + + let listener = TcpListener::bind(addr)?; let mut thread_number : u8 = 0; for stream in listener.incoming() { - handle_client(stream?, thread_number); + let players_arc_clone = Arc::clone(&players_arc); + //let _players_arc_clone_debug = Arc::clone(&players_arc); + handle_client(stream?, thread_number, players_arc_clone); + //_create_player_info_window(thread_number, _players_arc_clone_debug); if thread_number < 255 { thread_number += 1; } else {