diff --git a/src/command.rs b/src/command.rs index b5ae53e..45b8031 100644 --- a/src/command.rs +++ b/src/command.rs @@ -84,7 +84,7 @@ pub enum Command<'m> { /// sets the current player's password SetPass { password: &'m str }, /// sets the level spawn to the player's location - SetLevelSpawn, + SetLevelSpawn { overwrite_others: bool }, /// changes the levels weather Weather { weather_type: &'m str }, /// saves the current level @@ -155,7 +155,9 @@ impl<'m> Command<'m> { CMD_SETPASS => Self::SetPass { password: arguments.trim(), }, - CMD_SETLEVELSPAWN => Self::SetLevelSpawn, + CMD_SETLEVELSPAWN => Self::SetLevelSpawn { + overwrite_others: Self::next_bool(&mut arguments)?.unwrap_or_default(), + }, CMD_WEATHER => Self::Weather { weather_type: arguments, }, @@ -196,7 +198,7 @@ impl<'m> Command<'m> { Self::Ban { .. } => CMD_BAN, Self::AllowEntry { .. } => CMD_ALLOWENTRY, Self::SetPass { .. } => CMD_SETPASS, - Self::SetLevelSpawn => CMD_SETLEVELSPAWN, + Self::SetLevelSpawn { .. } => CMD_SETLEVELSPAWN, Self::Weather { .. } => CMD_WEATHER, Self::Save => CMD_SAVE, Self::Teleport { .. } => CMD_TELEPORT, @@ -259,7 +261,7 @@ impl<'m> Command<'m> { ], CMD_SETPASS => vec![c(""), "&fUpdates your password.".to_string()], CMD_SETLEVELSPAWN => vec![ - c(""), + c("[overwrite_others]"), "&fSets the level's spawn to your location.".to_string(), ], CMD_WEATHER => vec![ @@ -321,6 +323,21 @@ impl<'m> Command<'m> { Ok(n) } + /// gets the next bool from the command + fn next_bool(args: &mut &'m str) -> Result, String> { + if args.is_empty() { + return Ok(None); + } + let s = Self::next_string(args)?.to_lowercase(); + if s == "true" { + Ok(Some(true)) + } else if s == "false" { + Ok(Some(false)) + } else { + Err(format!("Expected bool, got {s}")) + } + } + /// processes the command >:3 pub fn process(self, data: &mut ServerData, own_id: i8) -> Vec { let mut messages = Vec::new(); @@ -546,14 +563,31 @@ impl<'m> Command<'m> { } } - Command::SetLevelSpawn => { + Command::SetLevelSpawn { overwrite_others } => { + let x = player.x; + let y = player.y; + let z = player.z; + let yaw = player.yaw; + let pitch = player.pitch; data.config.spawn = Some(ConfigCoordinatesWithOrientation { - x: player.x.to_f32(), - y: player.y.to_f32(), - z: player.z.to_f32(), - yaw: player.yaw, - pitch: player.pitch, + x: x.to_f32(), + y: y.to_f32(), + z: z.to_f32(), + yaw, + pitch, }); + if overwrite_others { + let packet = ServerPacket::SetSpawnPoint { + spawn_x: x, + spawn_y: y, + spawn_z: z, + spawn_yaw: yaw, + spawn_pitch: pitch, + }; + for player in &mut data.players { + player.packets_to_send.push(packet.clone()); + } + } data.config_needs_saving = true; messages.push("Level spawn updated!".to_string()); } diff --git a/src/packet/server.rs b/src/packet/server.rs index eeb25c8..76ff9a2 100644 --- a/src/packet/server.rs +++ b/src/packet/server.rs @@ -111,6 +111,14 @@ pub enum ServerPacket { EnvWeatherType { weather_type: WeatherType }, /// packet to set a block's position in the client's inventory SetInventoryOrder { order: u8, block: u8 }, + /// sets a player's spawn point without moving them + SetSpawnPoint { + spawn_x: f16, + spawn_y: f16, + spawn_z: f16, + spawn_yaw: u8, + spawn_pitch: u8, + }, ExtEntityTeleport { entity_id: i8, teleport_behavior: TeleportBehavior, @@ -148,6 +156,7 @@ impl ServerPacket { Self::HoldThis { .. } => 0x14, Self::EnvWeatherType { .. } => 0x1f, Self::SetInventoryOrder { .. } => 0x2c, + Self::SetSpawnPoint { .. } => 0x2e, Self::ExtEntityTeleport { .. } => 0x36, } } @@ -272,6 +281,18 @@ impl ServerPacket { } => writer.write_u8(*block).write_bool(*prevent_change), Self::EnvWeatherType { weather_type } => writer.write_u8(weather_type.into()), Self::SetInventoryOrder { order, block } => writer.write_u8(*order).write_u8(*block), + Self::SetSpawnPoint { + spawn_x, + spawn_y, + spawn_z, + spawn_yaw, + spawn_pitch, + } => writer + .write_f16(*spawn_x) + .write_f16(*spawn_y) + .write_f16(*spawn_z) + .write_u8(*spawn_yaw) + .write_u8(*spawn_pitch), Self::ExtEntityTeleport { entity_id, teleport_behavior,