From db3e0f846ed18b62bf8419b37e68262fb2e1ac02 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Tue, 28 Jul 2026 22:38:33 +0200 Subject: [PATCH 01/10] shorten list build --- src/command/list.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 From 2ddd24fc82c7989387708e27789ef5a5f6d8e44c Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Tue, 28 Jul 2026 22:38:59 +0200 Subject: [PATCH 02/10] split client module --- src/{client.rs => client/mod.rs} | 28 ++-------------------------- src/client/packet_type.rs | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) rename src/{client.rs => client/mod.rs} (85%) create mode 100644 src/client/packet_type.rs 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 From 72a0cf8c694edd69b0588a18c815df73677c2edc Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 12:48:38 +0200 Subject: [PATCH 03/10] add player name selector --- src/command/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/command/mod.rs b/src/command/mod.rs index c7057d6..bc8e79b 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,8 @@ 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}") } } } @@ -27,6 +29,7 @@ impl Display for Selector { mod say; mod list; mod kill; +mod ban; impl Command { pub fn raw(cmd: &str) -> Self { @@ -48,4 +51,8 @@ impl Command { pub fn kill() -> kill::KillCommand { kill::KillCommand::default() } + + pub fn ban() -> ban::BanCommand { + ban::BanCommand::default() + } } \ No newline at end of file From 958a6718ebf8910cacb7876cbdddf7c11ecad489 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 13:40:59 +0200 Subject: [PATCH 04/10] add ban --- src/command/ban.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/command/ban.rs diff --git a/src/command/ban.rs b/src/command/ban.rs new file mode 100644 index 0000000..cb18e91 --- /dev/null +++ b/src/command/ban.rs @@ -0,0 +1,26 @@ +#[derive(Default)] +pub struct BanCommand { + target: Option, + reason: 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 build(self) -> super::Command { + let target = self.target.unwrap_or(super::Selector::Player("nonexistent".to_string())); + let mut s = format!("ban {target}"); + if let Some(reason) = self.reason { + s.push_str(&format!(" {reason}")); + }; + super::Command(s) + } +} \ No newline at end of file From 9ff3aad199ddcf4a3e929587fa9a61df0310e736 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 13:42:58 +0200 Subject: [PATCH 05/10] add ip opt for ban --- src/command/ban.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/command/ban.rs b/src/command/ban.rs index cb18e91..9c27b3f 100644 --- a/src/command/ban.rs +++ b/src/command/ban.rs @@ -1,7 +1,8 @@ #[derive(Default)] pub struct BanCommand { target: Option, - reason: Option + reason: Option, + ip: Option } impl BanCommand { @@ -15,9 +16,15 @@ impl BanCommand { 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 mut s = format!("ban {target}"); + 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}")); }; From f835beef10e0c63ff81c5edcf8d1230a3a570ee0 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:20:49 +0200 Subject: [PATCH 06/10] add banlist --- src/command/banlist.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/command/mod.rs | 5 +++++ 2 files changed, 45 insertions(+) create mode 100644 src/command/banlist.rs 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/mod.rs b/src/command/mod.rs index bc8e79b..407e929 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -30,6 +30,7 @@ mod say; mod list; mod kill; mod ban; +mod banlist; impl Command { pub fn raw(cmd: &str) -> Self { @@ -55,4 +56,8 @@ impl Command { pub fn ban() -> ban::BanCommand { ban::BanCommand::default() } + + pub fn banlist() -> banlist::BanlistCommand { + banlist::BanlistCommand::new() + } } \ No newline at end of file From 4f202c8ade3e4b512eac7d9804df73a727574bdf Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:29:39 +0200 Subject: [PATCH 07/10] add defaultgamemode --- src/command/defaultgamemode.rs | 17 +++++++++++++++++ src/command/mod.rs | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/command/defaultgamemode.rs 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/mod.rs b/src/command/mod.rs index 407e929..674b0c5 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -26,11 +26,30 @@ impl Display for Selector { } } +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") + } + } +} + mod say; mod list; mod kill; mod ban; mod banlist; +mod defaultgamemode; impl Command { pub fn raw(cmd: &str) -> Self { @@ -60,4 +79,8 @@ impl Command { pub fn banlist() -> banlist::BanlistCommand { banlist::BanlistCommand::new() } + + pub fn defaultgamemode() -> defaultgamemode::DefaultGamemodeCommand { + defaultgamemode::DefaultGamemodeCommand::default() + } } \ No newline at end of file From ae432d79e9d52589c6cf02ea6a83a8af8789ed36 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:45:10 +0200 Subject: [PATCH 08/10] add op and deop --- src/command/deop.rs | 17 +++++++++++++++++ src/command/mod.rs | 10 ++++++++++ src/command/op.rs | 17 +++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/command/deop.rs create mode 100644 src/command/op.rs 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/mod.rs b/src/command/mod.rs index 674b0c5..eda185e 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -50,6 +50,8 @@ mod kill; mod ban; mod banlist; mod defaultgamemode; +mod op; +mod deop; impl Command { pub fn raw(cmd: &str) -> Self { @@ -83,4 +85,12 @@ impl Command { pub fn defaultgamemode() -> defaultgamemode::DefaultGamemodeCommand { defaultgamemode::DefaultGamemodeCommand::default() } + + pub fn op() -> op::OpCommand { + op::OpCommand::default() + } + + pub fn deop() -> deop::DeopCommand { + deop::DeopCommand::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 From 75779c6fe915983f524fd63449dc8258d8f266d2 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:55:25 +0200 Subject: [PATCH 09/10] add difficulty --- src/command/difficulty.rs | 19 +++++++++++++++++++ src/command/mod.rs | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/command/difficulty.rs 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/mod.rs b/src/command/mod.rs index eda185e..0e64490 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -44,6 +44,24 @@ impl Display for Gamemode { } } +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") + } + } +} + mod say; mod list; mod kill; @@ -52,6 +70,7 @@ mod banlist; mod defaultgamemode; mod op; mod deop; +mod difficulty; impl Command { pub fn raw(cmd: &str) -> Self { @@ -93,4 +112,8 @@ impl Command { pub fn deop() -> deop::DeopCommand { deop::DeopCommand::default() } + + pub fn difficulty() -> difficulty::DifficultyCommand { + difficulty::DifficultyCommand::default() + } } \ No newline at end of file From 1485cf975dfd51bb6c4eac0efefa75d582f06d2e Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:59:24 +0200 Subject: [PATCH 10/10] add gamemode --- src/command/gamemode.rs | 26 ++++++++++++++++++++++++++ src/command/mod.rs | 5 +++++ 2 files changed, 31 insertions(+) create mode 100644 src/command/gamemode.rs 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/mod.rs b/src/command/mod.rs index 0e64490..4ab2054 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -71,6 +71,7 @@ mod defaultgamemode; mod op; mod deop; mod difficulty; +mod gamemode; impl Command { pub fn raw(cmd: &str) -> Self { @@ -116,4 +117,8 @@ impl Command { pub fn difficulty() -> difficulty::DifficultyCommand { difficulty::DifficultyCommand::default() } + + pub fn gamemode() -> gamemode::GamemodeCommand { + gamemode::GamemodeCommand::default() + } } \ No newline at end of file