diff --git a/pumpkin/src/commands/gamemode.rs b/pumpkin/src/commands/gamemode.rs new file mode 100644 index 000000000..00b10e1eb --- /dev/null +++ b/pumpkin/src/commands/gamemode.rs @@ -0,0 +1,47 @@ +use super::Command; + +pub struct GamemodeCommand {} + +impl GamemodeCommand { + pub fn new() -> Self { + Self {} + } +} + +impl<'a> Command<'a> for GamemodeCommand { + const NAME: &'a str = "gamemode"; + + const DESCRIPTION: &'a str = "Changes the gamemode for a Player"; + + fn on_execute( + sender: &mut super::CommandSender<'a>, + command: String, + _server: &mut crate::server::Server, + ) { + let player = sender.as_mut_player().unwrap(); + let args: Vec<&str> = command.split_whitespace().collect(); + + if args.len() != 2 { + // todo red + player.send_message("Usage: /gamemode ".into()); + return; + } + + let mode_str = args[1].to_lowercase(); + match mode_str.parse() { + Ok(mode) => { + player.set_gamemode(mode); + player.send_message(format!("Set own game mode to {mode_str}").into()); + } + Err(_) => { + // todo red + player.send_message("Invalid gamemode".into()); + } + } + } + + // todo: support console, (name required) + fn player_required() -> bool { + true + } +} diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 796f858b1..47caa966e 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -1,8 +1,10 @@ +use gamemode::GamemodeCommand; use pumpkin::PumpkinCommand; use pumpkin_protocol::text::TextComponent; use crate::{client::Client, server::Server}; +mod gamemode; mod pumpkin; /// I think it would be great to split this up into a seperate crate, But idk how i should do that, Because we have to rely on Client and Server @@ -12,6 +14,11 @@ pub trait Command<'a> { const DESCRIPTION: &'a str; fn on_execute(sender: &mut CommandSender<'a>, command: String, server: &mut Server); + + /// Specifies wether the Command Sender has to be a Player + fn player_required() -> bool { + false + } } pub enum CommandSender<'a> { @@ -27,13 +34,38 @@ impl<'a> CommandSender<'a> { CommandSender::Player(c) => c.send_message(text), } } + + pub fn is_player(&mut self) -> bool { + match self { + CommandSender::Console => false, + CommandSender::Player(_) => true, + } + } + + pub fn is_console(&mut self) -> bool { + match self { + CommandSender::Console => true, + CommandSender::Player(_) => false, + } + } + pub fn as_mut_player(&mut self) -> Option<&mut Client> { + match self { + CommandSender::Player(client) => Some(client), + CommandSender::Console => None, + } + } } pub fn handle_command(sender: &mut CommandSender, command: String, server: &mut Server) { let command = command.to_lowercase(); + // an ugly mess i know if command.starts_with(PumpkinCommand::NAME) { PumpkinCommand::on_execute(sender, command, server); return; } + if command.starts_with(GamemodeCommand::NAME) { + GamemodeCommand::on_execute(sender, command, server); + return; + } // todo: red color sender.send_message("Command not Found".into()); } diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index ff4fb4678..0faf05f0a 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use pumpkin_protocol::VarInt; use serde::{Deserialize, Serialize}; @@ -42,13 +44,13 @@ pub enum Hand { Off, } -impl Hand { - pub fn from_varint(varint: VarInt) -> Self { - match varint { +impl From for Hand { + fn from(value: VarInt) -> Self { + match value { 0 => Self::Off, 1 => Self::Main, _ => { - log::info!("Unexpected Hand {}", varint); + log::info!("Unexpected Hand {}", value); Self::Main } } @@ -61,14 +63,14 @@ pub enum ChatMode { Hidden, } -impl ChatMode { - pub fn from_varint(varint: VarInt) -> Self { - match varint { +impl From for ChatMode { + fn from(value: VarInt) -> Self { + match value { 0 => Self::Enabled, 1 => Self::CommandsOnly, 2 => Self::Hidden, _ => { - log::info!("Unexpected ChatMode {}", varint); + log::info!("Unexpected ChatMode {}", value); Self::Enabled } } @@ -84,21 +86,40 @@ pub enum GameMode { Spectator, } -impl GameMode { - pub fn from_byte(byte: i8) -> Self { - match byte { +#[derive(Debug, PartialEq, Eq)] +pub struct ParseGameModeError; + +impl FromStr for GameMode { + type Err = ParseGameModeError; + + fn from_str(s: &str) -> Result { + match s { + "survival" => Ok(Self::Survival), + "creative" => Ok(Self::Creative), + "adventure" => Ok(Self::Adventure), + "spectator" => Ok(Self::Spectator), + _ => Err(ParseGameModeError), + } + } +} + +impl From for GameMode { + fn from(value: i8) -> Self { + match value { -1 => GameMode::Undefined, 0 => GameMode::Survival, 1 => GameMode::Creative, 2 => GameMode::Adventure, 3 => GameMode::Spectator, _ => { - log::info!("Unexpected GameMode {}", byte); + log::info!("Unexpected GameMode {}", value); Self::Survival } } } +} +impl GameMode { pub fn to_byte(self) -> i8 { match self { Self::Undefined => -1,