Skip to content

Commit

Permalink
feat(commands): vanilla arg types and props, fix some graph issues
Browse files Browse the repository at this point in the history
  • Loading branch information
radstevee committed Dec 29, 2024
1 parent f7971f1 commit 5080189
Show file tree
Hide file tree
Showing 14 changed files with 446 additions and 164 deletions.
15 changes: 14 additions & 1 deletion src/lib/commands/src/arg/parser/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ use std::sync::{Arc, Mutex};

use crate::{ctx::CommandContext, input::CommandInput, ParserResult};

use super::{utils::error, ArgumentParser};
use super::{
utils::error,
vanilla::{
int::IntParserFlags, MinecraftArgument, MinecraftArgumentProperties, MinecraftArgumentType,
},
ArgumentParser,
};

pub struct IntParser;

Expand All @@ -22,4 +28,11 @@ impl ArgumentParser for IntParser {
{
IntParser
}

fn vanilla(&self) -> MinecraftArgument {
MinecraftArgument {
argument_type: MinecraftArgumentType::Int,
props: MinecraftArgumentProperties::Int(IntParserFlags::default()),
}
}
}
2 changes: 2 additions & 0 deletions src/lib/commands/src/arg/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ use crate::{ctx::CommandContext, input::CommandInput, ParserResult};
pub mod int;
pub mod string;
pub mod utils;
pub mod vanilla;

pub trait ArgumentParser: Send + Sync {
fn parse(&self, context: Arc<CommandContext>, input: Arc<Mutex<CommandInput>>) -> ParserResult;
fn new() -> Self
where
Self: Sized;
fn vanilla(&self) -> vanilla::MinecraftArgument;
}
107 changes: 70 additions & 37 deletions src/lib/commands/src/arg/parser/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ use std::sync::{Arc, Mutex};

use crate::{ctx::CommandContext, input::CommandInput, ParserResult};

use super::{utils::parser_error, ArgumentParser};
use super::{
utils::parser_error,
vanilla::{
string::StringParsingBehavior, MinecraftArgument, MinecraftArgumentProperties,
MinecraftArgumentType,
},
ArgumentParser,
};

pub struct SingleStringParser;

Expand All @@ -22,6 +29,13 @@ impl ArgumentParser for SingleStringParser {
{
SingleStringParser
}

fn vanilla(&self) -> MinecraftArgument {
MinecraftArgument {
argument_type: MinecraftArgumentType::String,
props: MinecraftArgumentProperties::String(StringParsingBehavior::default()),
}
}
}

pub struct GreedyStringParser;
Expand Down Expand Up @@ -57,56 +71,68 @@ impl ArgumentParser for GreedyStringParser {
{
GreedyStringParser
}

fn vanilla(&self) -> MinecraftArgument {
MinecraftArgument {
argument_type: MinecraftArgumentType::String,
props: MinecraftArgumentProperties::String(StringParsingBehavior::Greedy),
}
}
}
pub struct QuotedStringParser;

impl ArgumentParser for QuotedStringParser {
fn parse(&self, _ctx: Arc<CommandContext>, input: Arc<Mutex<CommandInput>>) -> ParserResult {
let mut input = input.lock().unwrap();

input.skip_whitespace(u32::MAX, false);

if input.peek() != Some('"') {
return Err(parser_error("expected opening quote"));
}

input.read(1);

let mut result = String::new();
let mut escaped = false;

while input.has_remaining_input() {
let current = input.peek();

match current {
None => return Err(parser_error("unterminated quoted string")),
Some(c) => {
input.read(1);

if escaped {
match c {
'"' | '\\' => result.push(c),
'n' => result.push('\n'),
'r' => result.push('\r'),
't' => result.push('\t'),
_ => {
result.push('\\');
result.push(c);
// If it starts with a quote, use quoted string parsing
if input.peek() == Some('"') {
input.read(1); // consume the opening quote

let mut result = String::new();
let mut escaped = false;

while input.has_remaining_input() {
let current = input.peek();

match current {
None => return Err(parser_error("unterminated quoted string")),
Some(c) => {
input.read(1);

if escaped {
match c {
'"' | '\\' => result.push(c),
'n' => result.push('\n'),
'r' => result.push('\r'),
't' => result.push('\t'),
_ => {
result.push('\\');
result.push(c);
}
}
escaped = false;
} else {
match c {
'"' => return Ok(Box::new(result)),
'\\' => escaped = true,
_ => result.push(c),
}
}
escaped = false;
} else {
match c {
'"' => return Ok(Box::new(result)),
'\\' => escaped = true,
_ => result.push(c),
}
}
}
}
}

Err(parser_error("unterminated quoted string"))
Err(parser_error("unterminated quoted string"))
} else {
// If no quotes, parse as single word
if input.peek_string().is_empty() {
return Err(parser_error("input cannot be empty"));
}

Ok(Box::new(input.read_string()))
}
}

fn new() -> Self
Expand All @@ -115,4 +141,11 @@ impl ArgumentParser for QuotedStringParser {
{
QuotedStringParser
}

fn vanilla(&self) -> MinecraftArgument {
MinecraftArgument {
argument_type: MinecraftArgumentType::String,
props: MinecraftArgumentProperties::String(StringParsingBehavior::Quotable),
}
}
}
42 changes: 42 additions & 0 deletions src/lib/commands/src/arg/parser/vanilla/float.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::io::Write;

use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts, NetEncodeResult};
use tokio::io::AsyncWrite;

#[derive(Clone, Debug, PartialEq, Default)]
pub struct FloatParserFlags {
pub min: Option<f32>,
pub max: Option<f32>,
}

impl NetEncode for FloatParserFlags {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> {
let mut flags = 0u8;
if self.min.is_some() {
flags |= 0x01;
}
if self.max.is_some() {
flags |= 0x02;
}
flags.encode(writer, opts)?;
self.min.encode(writer, opts)?;
self.max.encode(writer, opts)
}

async fn encode_async<W: AsyncWrite + Unpin>(
&self,
writer: &mut W,
opts: &NetEncodeOpts,
) -> NetEncodeResult<()> {
let mut flags = 0u8;
if self.min.is_some() {
flags |= 0x01;
}
if self.max.is_some() {
flags |= 0x02;
}
flags.encode_async(writer, opts).await?;
self.min.encode_async(writer, opts).await?;
self.max.encode_async(writer, opts).await
}
}
42 changes: 42 additions & 0 deletions src/lib/commands/src/arg/parser/vanilla/int.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::io::Write;

use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts, NetEncodeResult};
use tokio::io::AsyncWrite;

#[derive(Clone, Debug, PartialEq, Default)]
pub struct IntParserFlags {
pub min: Option<i32>,
pub max: Option<i32>,
}

impl NetEncode for IntParserFlags {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> {
let mut flags = 0u8;
if self.min.is_some() {
flags |= 0x01;
}
if self.max.is_some() {
flags |= 0x02;
}
flags.encode(writer, opts)?;
self.min.encode(writer, opts)?;
self.max.encode(writer, opts)
}

async fn encode_async<W: AsyncWrite + Unpin>(
&self,
writer: &mut W,
opts: &NetEncodeOpts,
) -> NetEncodeResult<()> {
let mut flags = 0u8;
if self.min.is_some() {
flags |= 0x01;
}
if self.max.is_some() {
flags |= 0x02;
}
flags.encode_async(writer, opts).await?;
self.min.encode_async(writer, opts).await?;
self.max.encode_async(writer, opts).await
}
}
42 changes: 42 additions & 0 deletions src/lib/commands/src/arg/parser/vanilla/long.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::io::Write;

use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts, NetEncodeResult};
use tokio::io::AsyncWrite;

#[derive(Clone, Debug, PartialEq, Default)]
pub struct LongParserFlags {
pub min: Option<i64>,
pub max: Option<i64>,
}

impl NetEncode for LongParserFlags {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> {
let mut flags = 0u8;
if self.min.is_some() {
flags |= 0x01;
}
if self.max.is_some() {
flags |= 0x02;
}
flags.encode(writer, opts)?;
self.min.encode(writer, opts)?;
self.max.encode(writer, opts)
}

async fn encode_async<W: AsyncWrite + Unpin>(
&self,
writer: &mut W,
opts: &NetEncodeOpts,
) -> NetEncodeResult<()> {
let mut flags = 0u8;
if self.min.is_some() {
flags |= 0x01;
}
if self.max.is_some() {
flags |= 0x02;
}
flags.encode_async(writer, opts).await?;
self.min.encode_async(writer, opts).await?;
self.max.encode_async(writer, opts).await
}
}
Loading

0 comments on commit 5080189

Please sign in to comment.