Compare commits

...

10 commits

Author SHA1 Message Date
Raptorox
1485cf975d
add gamemode 2026-08-01 14:59:24 +02:00
Raptorox
75779c6fe9
add difficulty 2026-08-01 14:55:25 +02:00
Raptorox
ae432d79e9
add op and deop 2026-08-01 14:45:10 +02:00
Raptorox
4f202c8ade
add defaultgamemode 2026-08-01 14:29:39 +02:00
Raptorox
f835beef10
add banlist 2026-08-01 14:24:17 +02:00
Raptorox
9ff3aad199
add ip opt for ban 2026-08-01 13:43:35 +02:00
Raptorox
958a6718eb
add ban 2026-08-01 13:40:59 +02:00
Raptorox
72a0cf8c69
add player name selector 2026-08-01 12:48:38 +02:00
Raptorox
2ddd24fc82
split client module 2026-07-28 22:38:59 +02:00
Raptorox
db3e0f846e
shorten list build 2026-07-28 22:38:33 +02:00
11 changed files with 272 additions and 32 deletions

View file

@ -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<i32> for PacketType {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
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 {

25
src/client/packet_type.rs Normal file
View file

@ -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<i32> for PacketType {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
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(())
}
}
}

33
src/command/ban.rs Normal file
View file

@ -0,0 +1,33 @@
#[derive(Default)]
pub struct BanCommand {
target: Option<super::Selector>,
reason: Option<String>,
ip: Option<bool>
}
impl BanCommand {
pub fn target(mut self, target: super::Selector) -> Self {
self.target = Some(target);
self
}
pub fn reason(mut self, reason: impl Into<String>) -> 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)
}
}

40
src/command/banlist.rs Normal file
View file

@ -0,0 +1,40 @@
use std::marker::PhantomData;
#[derive(Default)]
pub struct BanlistCommand<State> {
state: PhantomData<State>
}
pub struct NoFilter;
pub struct Ips;
pub struct Players;
impl BanlistCommand<NoFilter> {
pub(crate) fn new() -> Self {
Self { state: PhantomData }
}
pub fn players(self) -> BanlistCommand<Players> {
BanlistCommand { state: PhantomData }
}
pub fn ips(self) -> BanlistCommand<Ips> {
BanlistCommand { state: PhantomData }
}
pub fn build(self) -> super::Command {
super::Command::raw("banlist")
}
}
impl BanlistCommand<Players> {
pub fn build(self) -> super::Command {
super::Command::raw("banlist players")
}
}
impl BanlistCommand<Ips> {
pub fn build(self) -> super::Command {
super::Command::raw("banlist ips")
}
}

View file

@ -0,0 +1,17 @@
#[derive(Default)]
pub struct DefaultGamemodeCommand {
gamemode: Option<super::Gamemode>
}
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)
}
}

17
src/command/deop.rs Normal file
View file

@ -0,0 +1,17 @@
#[derive(Default)]
pub struct DeopCommand {
target: Option<super::Selector>
}
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)
}
}

19
src/command/difficulty.rs Normal file
View file

@ -0,0 +1,19 @@
#[derive(Default)]
pub struct DifficultyCommand {
difficulty: Option<super::Difficulty>
}
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)
}
}

26
src/command/gamemode.rs Normal file
View file

@ -0,0 +1,26 @@
#[derive(Default)]
pub struct GamemodeCommand {
gamemode: Option<super::Gamemode>,
target: Option<super::Selector>
}
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)
}
}

View file

@ -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)
}
}

View file

@ -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::NoFilter> {
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()
}
}

17
src/command/op.rs Normal file
View file

@ -0,0 +1,17 @@
#[derive(Default)]
pub struct OpCommand {
target: Option<super::Selector>
}
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)
}
}