diff --git a/src/client.rs b/src/client/mod.rs similarity index 85% rename from src/client.rs rename to src/client/mod.rs index 83354e3..207c979 100644 --- a/src/client.rs +++ b/src/client/mod.rs @@ -1,30 +1,6 @@ use std::{fmt::Display, io::{self, Read, Write}, net::{TcpStream, ToSocketAddrs}}; - -#[derive(Clone, Copy, PartialEq)] -enum PacketType { - Login = 3, - Command = 2, - Response = 0 -} - -impl PacketType { - fn to_le_bytes(self) -> [u8; 4] { - (self as i32).to_le_bytes() - } -} - -impl TryFrom for PacketType { - type Error = (); - - fn try_from(value: i32) -> Result { - match value { - x if x == Self::Login as i32 => Ok(Self::Login), - x if x == Self::Command as i32 => Ok(Self::Command), - x if x == Self::Response as i32 => Ok(Self::Response), - _ => Err(()) - } - } -} +mod packet_type; +use packet_type::PacketType; #[derive(Debug)] pub enum RconError { diff --git a/src/client/packet_type.rs b/src/client/packet_type.rs new file mode 100644 index 0000000..bc4e0ed --- /dev/null +++ b/src/client/packet_type.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Copy, PartialEq)] +pub enum PacketType { + Login = 3, + Command = 2, + Response = 0 +} + +impl PacketType { + pub fn to_le_bytes(self) -> [u8; 4] { + (self as i32).to_le_bytes() + } +} + +impl TryFrom for PacketType { + type Error = (); + + fn try_from(value: i32) -> Result { + match value { + x if x == Self::Login as i32 => Ok(Self::Login), + x if x == Self::Command as i32 => Ok(Self::Command), + x if x == Self::Response as i32 => Ok(Self::Response), + _ => Err(()) + } + } +} \ No newline at end of file diff --git a/src/command/ban.rs b/src/command/ban.rs new file mode 100644 index 0000000..9c27b3f --- /dev/null +++ b/src/command/ban.rs @@ -0,0 +1,33 @@ +#[derive(Default)] +pub struct BanCommand { + target: Option, + reason: Option, + ip: Option +} + +impl BanCommand { + pub fn target(mut self, target: super::Selector) -> Self { + self.target = Some(target); + self + } + + pub fn reason(mut self, reason: impl Into) -> Self { + self.reason = Some(reason.into()); + self + } + + pub fn ip(mut self) -> Self { + self.ip = Some(true); + self + } + + pub fn build(self) -> super::Command { + let target = self.target.unwrap_or(super::Selector::Player("nonexistent".to_string())); + let ip = self.ip.unwrap_or(false); + let mut s = if ip { format!("ban-ip {target}") } else { format!("ban {target}") }; + if let Some(reason) = self.reason { + s.push_str(&format!(" {reason}")); + }; + super::Command(s) + } +} \ No newline at end of file diff --git a/src/command/banlist.rs b/src/command/banlist.rs new file mode 100644 index 0000000..dd227e5 --- /dev/null +++ b/src/command/banlist.rs @@ -0,0 +1,40 @@ +use std::marker::PhantomData; + +#[derive(Default)] +pub struct BanlistCommand { + state: PhantomData +} + +pub struct NoFilter; +pub struct Ips; +pub struct Players; + +impl BanlistCommand { + pub(crate) fn new() -> Self { + Self { state: PhantomData } + } + + pub fn players(self) -> BanlistCommand { + BanlistCommand { state: PhantomData } + } + + pub fn ips(self) -> BanlistCommand { + BanlistCommand { state: PhantomData } + } + + pub fn build(self) -> super::Command { + super::Command::raw("banlist") + } +} + +impl BanlistCommand { + pub fn build(self) -> super::Command { + super::Command::raw("banlist players") + } +} + +impl BanlistCommand { + pub fn build(self) -> super::Command { + super::Command::raw("banlist ips") + } +} \ No newline at end of file diff --git a/src/command/defaultgamemode.rs b/src/command/defaultgamemode.rs new file mode 100644 index 0000000..324df9d --- /dev/null +++ b/src/command/defaultgamemode.rs @@ -0,0 +1,17 @@ +#[derive(Default)] +pub struct DefaultGamemodeCommand { + gamemode: Option +} + +impl DefaultGamemodeCommand { + pub fn gamemode(mut self, gamemode: super::Gamemode) -> Self { + self.gamemode = Some(gamemode); + self + } + + pub fn build(self) -> super::Command { + let gamemode = self.gamemode.unwrap_or(super::Gamemode::Survival); + let s = format!("defaultgamemode {gamemode}"); + super::Command(s) + } +} \ No newline at end of file diff --git a/src/command/deop.rs b/src/command/deop.rs new file mode 100644 index 0000000..5f4eda3 --- /dev/null +++ b/src/command/deop.rs @@ -0,0 +1,17 @@ +#[derive(Default)] +pub struct DeopCommand { + target: Option +} + +impl DeopCommand { + pub fn target(mut self, target: super::Selector) -> Self { + self.target = Some(target); + self + } + + pub fn build(self) -> super::Command { + let target = self.target.unwrap_or(super::Selector::Executor); + let s = format!("deop {target}"); + super::Command(s) + } +} \ No newline at end of file diff --git a/src/command/difficulty.rs b/src/command/difficulty.rs new file mode 100644 index 0000000..9a663c8 --- /dev/null +++ b/src/command/difficulty.rs @@ -0,0 +1,19 @@ +#[derive(Default)] +pub struct DifficultyCommand { + difficulty: Option +} + +impl DifficultyCommand { + pub fn difficulty(mut self, difficulty: super::Difficulty) -> Self { + self.difficulty = Some(difficulty); + self + } + + pub fn build(self) -> super::Command { + let mut s = format!("difficulty"); + if let Some(difficulty) = self.difficulty { + s.push_str(&format!(" {difficulty}")) + }; + super::Command(s) + } +} \ No newline at end of file diff --git a/src/command/gamemode.rs b/src/command/gamemode.rs new file mode 100644 index 0000000..d6759ae --- /dev/null +++ b/src/command/gamemode.rs @@ -0,0 +1,26 @@ +#[derive(Default)] +pub struct GamemodeCommand { + gamemode: Option, + target: Option +} + +impl GamemodeCommand { + pub fn gamemode(mut self, gamemode: super::Gamemode) -> Self { + self.gamemode = Some(gamemode); + self + } + + pub fn target(mut self, target: super::Selector) -> Self { + self.target = Some(target); + self + } + + pub fn build(self) -> super::Command { + let gamemode = self.gamemode.unwrap_or(super::Gamemode::Survival); + let mut s = format!("defaultgamemode {gamemode}"); + if let Some(target) = self.target { + s.push_str(&format!(" {target}")) + } + super::Command(s) + } +} \ No newline at end of file diff --git a/src/command/list.rs b/src/command/list.rs index fed9ccd..fc42328 100644 --- a/src/command/list.rs +++ b/src/command/list.rs @@ -11,10 +11,7 @@ impl ListCommand { pub fn build(self) -> super::Command { let uuids = self.uuids.unwrap_or(false); - let mut s = format!("list"); - if uuids { - s.push_str(" uuids"); - } + let s = format!("list {}", if uuids { "uuids" } else {""} ); super::Command(s) } } \ No newline at end of file diff --git a/src/command/mod.rs b/src/command/mod.rs index c7057d6..4ab2054 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -8,7 +8,8 @@ pub enum Selector { AllPlayers, // @a AllEntities, // @e Executor, // @s - NearestEntity // @n + NearestEntity, // @n, + Player(String) } impl Display for Selector { @@ -19,7 +20,44 @@ impl Display for Selector { Self::AllPlayers => write!(f, "@a"), Self::AllEntities => write!(f, "@e"), Self::Executor => write!(f, "@s"), - Self::NearestEntity => write!(f, "@n") + Self::NearestEntity => write!(f, "@n"), + Self::Player(name) => write!(f, "{name}") + } + } +} + +pub enum Gamemode { + Survival, + Creative, + Adventure, + Spectator +} + +impl Display for Gamemode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Survival => write!(f, "survival"), + Self::Creative => write!(f, "creative"), + Self::Adventure => write!(f, "adventure"), + Self::Spectator => write!(f, "spectator") + } + } +} + +pub enum Difficulty { + Peaceful, + Easy, + Normal, + Hard +} + +impl Display for Difficulty { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Peaceful => write!(f, "peaceful"), + Self::Easy => write!(f, "easy"), + Self::Normal => write!(f, "normal"), + Self::Hard => write!(f, "hard") } } } @@ -27,6 +65,13 @@ impl Display for Selector { mod say; mod list; mod kill; +mod ban; +mod banlist; +mod defaultgamemode; +mod op; +mod deop; +mod difficulty; +mod gamemode; impl Command { pub fn raw(cmd: &str) -> Self { @@ -48,4 +93,32 @@ impl Command { pub fn kill() -> kill::KillCommand { kill::KillCommand::default() } + + pub fn ban() -> ban::BanCommand { + ban::BanCommand::default() + } + + pub fn banlist() -> banlist::BanlistCommand { + banlist::BanlistCommand::new() + } + + pub fn defaultgamemode() -> defaultgamemode::DefaultGamemodeCommand { + defaultgamemode::DefaultGamemodeCommand::default() + } + + pub fn op() -> op::OpCommand { + op::OpCommand::default() + } + + pub fn deop() -> deop::DeopCommand { + deop::DeopCommand::default() + } + + pub fn difficulty() -> difficulty::DifficultyCommand { + difficulty::DifficultyCommand::default() + } + + pub fn gamemode() -> gamemode::GamemodeCommand { + gamemode::GamemodeCommand::default() + } } \ No newline at end of file diff --git a/src/command/op.rs b/src/command/op.rs new file mode 100644 index 0000000..af05c56 --- /dev/null +++ b/src/command/op.rs @@ -0,0 +1,17 @@ +#[derive(Default)] +pub struct OpCommand { + target: Option +} + +impl OpCommand { + pub fn target(mut self, target: super::Selector) -> Self { + self.target = Some(target); + self + } + + pub fn build(self) -> super::Command { + let target = self.target.unwrap_or(super::Selector::Executor); + let s = format!("op {target}"); + super::Command(s) + } +} \ No newline at end of file