diff --git a/cli/src/cli.rs b/cli/src/cli.rs index a358611..cec4b97 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,15 +1,16 @@ //! Spanned-clap, lol use itertools::Itertools; -use std::{marker::PhantomData, path::PathBuf, str::FromStr}; +use std::{borrow::Cow, marker::PhantomData, path::PathBuf, str::FromStr}; use aott::prelude::*; use oxcr_protocol::{ aott::{ self, pfn_type, - text::{ascii::ident, digits, inline_whitespace, int, whitespace}, + text::{ascii::ident, digits, inline_whitespace}, }, - bytes::{BufMut, Bytes, BytesMut}, + bytes::Bytes, + nbt::NbtTagType, tracing::{level_filters::LevelFilter, Level}, }; @@ -33,6 +34,7 @@ pub enum CliCommand { Help, VarInt(ByteInput), Decompress(ByteInput), + Nbt(NbtTagType, ByteInput), } #[derive(Debug, Clone)] @@ -48,6 +50,7 @@ pub enum Flag { Decode(ByteInput), VarInt(ByteInput), Decompress(ByteInput), + Nbt(NbtTagType, ByteInput), } #[derive(Debug)] @@ -147,6 +150,28 @@ fn flags(input: &str) -> Vec { Flag::VarInt(byte_input(input)?) } FlagName::Short("h") | FlagName::Long("help") => Flag::Help, + FlagName::Short("n") | FlagName::Long("nbt") => { + one_of(" =")(input)?; + let before_nbt_tag = input.offset; + + let nbt_tag = match ident(input)? { + "compound" => NbtTagType::Compound, + tag => { + return Err(ParseError::Expected { + expected: Expectation::AnyOfStr(vec!["compound"]), + found: tag.chars().next().expect("no tag at all"), + at: input.span_since(before_nbt_tag).into(), + help: Some(Cow::Borrowed("an NBT tag type is: Compound")), + }) + } + }; + + just(",")(input)?; + + inline_whitespace().check_with(input)?; + + Flag::Nbt(nbt_tag, byte_input(input)?) + } FlagName::Short(flag) | FlagName::Long(flag) => Err(ParseError::UnknownFlag { flag: flag.to_owned(), at: input.span_since(before).into(), @@ -168,6 +193,7 @@ fn flags_handle<'a>( Flag::Decode(input) => cli.command = CliCommand::Decode(input), Flag::VarInt(input) => cli.command = CliCommand::VarInt(input), Flag::Decompress(input) => cli.command = CliCommand::Decompress(input), + Flag::Nbt(tag, input) => cli.command = CliCommand::Nbt(tag, input), } } try { flags(input)?.into_iter().for_each(|flag| handle(cli, flag)) } @@ -177,7 +203,7 @@ fn flags_handle<'a>( pub fn yay(input: &str) -> Cli { try { let mut cli = Cli { - level: LevelFilter::OFF, + level: LevelFilter::INFO, command: CliCommand::Help, }; diff --git a/cli/src/error.rs b/cli/src/error.rs index 963dac2..9d2b0ed 100644 --- a/cli/src/error.rs +++ b/cli/src/error.rs @@ -64,6 +64,8 @@ pub enum ParseError { pub enum Expectation { #[error("{}", any_of(.0))] AnyOf(Vec), + #[error("{}", any_of(.0))] + AnyOfStr(Vec<&'static str>), #[error("end of input")] EndOfInput, #[error("a digit with radix {_0}")] diff --git a/cli/src/main.rs b/cli/src/main.rs index 07220c7..0f21c28 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] #![feature(iterator_try_collect, try_blocks)] use oxcr_protocol::{ @@ -5,19 +6,20 @@ use oxcr_protocol::{ bytes::Bytes, error::Error, logging::CraftLayer, - miette::{self, bail, IntoDiagnostic, Report}, + miette::{bail, IntoDiagnostic, Report}, model::{ - packets::{play::LoginPlay, Packet, PacketContext, SerializedPacket}, + packets::{play::LoginPlay, Packet, SerializedPacket}, VarInt, }, - ser::{BytesSource, Deserialize, Serialize, WithSource}, + nbt::Nbt, + ser::{BytesSource, Deserialize, WithSource}, tracing::debug, }; use tracing_subscriber::{ prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter, }; -use crate::cli::{ByteInput, Cli, CliCommand}; +use crate::cli::{ByteInput, CliCommand}; mod cli; mod error; @@ -39,7 +41,7 @@ fn run(_path: String, args: &str) -> Result<(), Report> { .with(CraftLayer) .set_default(); - debug!("{:?}", cli); + debug!(%cli.level, ?cli.command); match cli.command { CliCommand::Help => help(), @@ -62,7 +64,15 @@ fn run(_path: String, args: &str) -> Result<(), Report> { .map_err(reconcile(bytes))? ); } - CliCommand::Decompress(inp) => todo!(), + CliCommand::Nbt(tag, inp) => { + let bytes = read_byte_input(inp)?; + let nbt = Nbt::single + .parse_with_context(&bytes, tag) + .map_err(reconcile(bytes))?; + + println!("{nbt:#?}"); + } + CliCommand::Decompress(_inp) => todo!(), }; Ok(()) @@ -111,16 +121,20 @@ fn main() -> Result<(), Report> { fn help() { println!( r#" - This is the OxCraft CLI. Here you can serialize and deserialize packets (currently only LoginPlay). +This is the OxCraft CLI. Here you can serialize and deserialize packets (currently only LoginPlay) and NBT. + +Example usage: +cargo run -p oxcr_cli -- -Dd 0xbd7d9a9f7e +This will turn on debug logging and deserialize LoginPlay from the data 0xbd7d etc. - Example usage: - cargo run -p oxcr_cli -- -Dd 0xbd7d9a9f7e - This will deserialize turn on debug logging and deserialize LoginPlay from the data 0xbd7d etc. +Clarifications: + is either inline binary (0b...), octal (0o...), hexadecimal (0x...), or decimal data (0d...); or it could be a path like ./mydata.bin - Flags: - -l --level what log level - -D --debug same as --level debug - -d --deserialize --decode deserializes a packet from , then debug-logs it. +Flags: +-l --level what log level (error, warn, info, debug, trace) +-D --debug same as --level debug +-d --deserialize --decode deserializes a packet from , then debug-logs it. +-n --nbt , deserializes a from . is (right now only) compound "# ); } diff --git a/protocol/src/nbt.rs b/protocol/src/nbt.rs index cbc9489..5c8870e 100644 --- a/protocol/src/nbt.rs +++ b/protocol/src/nbt.rs @@ -261,7 +261,6 @@ impl NbtTag { #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[doc(hidden)] pub enum NbtTagType { End = 0, Byte,