pub mod brigadier;
pub mod minecraft;
use self::{
brigadier::BrigadierStringType,
minecraft::{
coordinate::{MinecraftBlockPos, MinecraftRotation, MinecraftVec3},
entity::MinecraftSelector,
nbt::MinecraftNbtPath,
range::MinecraftRange,
resource::{MinecraftResource, MinecraftResourceLocation, MinecraftResourceOrTag},
MinecraftDimension, MinecraftEntityAnchor, MinecraftFunction, MinecraftHeightmap,
MinecraftMessage, MinecraftObjective, MinecraftObjectiveCriteria, MinecraftOperation,
MinecraftScoreHolder, MinecraftScoreboardSlot, MinecraftSwizzle, MinecraftTeam,
MinecraftTime,
},
};
use crate::{
generator::parser::command::{
argument::minecraft::{block::MinecraftBlockPredicate, entity::MinecraftEntity},
resource_location::ResourceLocation,
},
utils::Map0,
};
use serde::{Deserialize, Serialize};
use std::{str::FromStr, usize};
trait ArgumentValue<'l>: Sized {
fn parse(string: &'l str) -> Result<(Self, usize), String>;
}
trait ArgumentValueEnum: FromStr + Sized {}
impl<E: ArgumentValueEnum> ArgumentValue<'_> for E {
fn parse(string: &str) -> Result<(Self, usize), String> {
let (value, len) = brigadier::parse_unquoted_string(string);
let value = Self::from_str(value).map_err(|_| format!("Invalid value \"{}\"", value))?;
Ok((value, len))
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Argument<'l> {
BrigadierDouble(f64),
BrigadierInteger(i32),
BrigadierString(&'l str),
MinecraftBlockPos(MinecraftBlockPos),
MinecraftBlockPredicate(MinecraftBlockPredicate<'l>),
MinecraftDimension(MinecraftDimension<'l>),
MinecraftEntity(MinecraftEntity<'l>),
MinecraftEntityAnchor(MinecraftEntityAnchor),
MinecraftFunction(MinecraftFunction<'l>),
MinecraftIntRange(MinecraftRange<i32>),
MinecraftHeightmap(MinecraftHeightmap),
MinecraftMessage(MinecraftMessage<'l>),
MinecraftNbtPath(MinecraftNbtPath<'l>),
MinecraftObjective(MinecraftObjective<'l>),
MinecraftObjectiveCriteria(MinecraftObjectiveCriteria<'l>),
MinecraftOperation(MinecraftOperation),
MinecraftResource(MinecraftResource<'l>),
MinecraftResourceLocation(MinecraftResourceLocation<'l>),
MinecraftResourceOrTag(MinecraftResourceOrTag<'l>),
MinecraftRotation(MinecraftRotation),
MinecraftScoreHolder(MinecraftScoreHolder<'l>),
MinecraftScoreboardSlot(MinecraftScoreboardSlot<'l>),
MinecraftSwizzle(MinecraftSwizzle),
MinecraftTeam(MinecraftTeam<'l>),
MinecraftTime(MinecraftTime),
MinecraftVec3(MinecraftVec3),
Unknown(&'l str),
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(tag = "parser", content = "properties")]
pub enum ArgumentParser {
#[serde(rename = "brigadier:bool")]
BrigadierBool,
#[serde(rename = "brigadier:double")]
BrigadierDouble(Option<BrigadierDoubleProperties>),
#[serde(rename = "brigadier:float")]
BrigadierFloat(Option<BrigadierFloatProperties>),
#[serde(rename = "brigadier:integer")]
BrigadierInteger(Option<BrigadierIntegerProperties>),
#[serde(rename = "brigadier:string")]
BrigadierString {
#[serde(rename = "type")]
type_: BrigadierStringType,
},
#[serde(rename = "minecraft:angle")]
MinecraftAngle,
#[serde(rename = "minecraft:block_pos")]
MinecraftBlockPos,
#[serde(rename = "minecraft:block_predicate")]
MinecraftBlockPredicate,
#[serde(rename = "minecraft:block_state")]
MinecraftBlockState,
#[serde(rename = "minecraft:color")]
MinecraftColor,
#[serde(rename = "minecraft:column_pos")]
MinecraftColumnPos,
#[serde(rename = "minecraft:component")]
MinecraftComponent,
#[serde(rename = "minecraft:dimension")]
MinecraftDimension,
#[serde(rename = "minecraft:entity")]
MinecraftEntity {
#[serde(rename = "type")]
type_: MinecraftEntityType,
amount: MinecraftAmount,
},
#[serde(rename = "minecraft:entity_anchor")]
MinecraftEntityAnchor,
#[serde(rename = "minecraft:entity_summon")]
MinecraftEntitySummon,
#[serde(rename = "minecraft:function")]
MinecraftFunction,
#[serde(rename = "minecraft:game_profile")]
MinecraftGameProfile,
#[serde(rename = "minecraft:gamemode")]
MinecraftGamemode,
#[serde(rename = "minecraft:heightmap")]
MinecraftHeightmap,
#[serde(rename = "minecraft:int_range")]
MinecraftIntRange,
#[serde(rename = "minecraft:item_enchantment")]
MinecraftItemEnchantment,
#[serde(rename = "minecraft:item_predicate")]
MinecraftItemPredicate,
#[serde(rename = "minecraft:item_slot")]
MinecraftItemSlot,
#[serde(rename = "minecraft:item_stack")]
MinecraftItemStack,
#[serde(rename = "minecraft:message")]
MinecraftMessage,
#[serde(rename = "minecraft:mob_effect")]
MinecraftMobEffect,
#[serde(rename = "minecraft:nbt_compound_tag")]
MinecraftNbtCompoundTag,
#[serde(rename = "minecraft:nbt_path")]
MinecraftNbtPath,
#[serde(rename = "minecraft:nbt_tag")]
MinecraftNbtTag,
#[serde(rename = "minecraft:objective")]
MinecraftObjective,
#[serde(rename = "minecraft:objective_criteria")]
MinecraftObjectiveCriteria,
#[serde(rename = "minecraft:operation")]
MinecraftOperation,
#[serde(rename = "minecraft:particle")]
MinecraftParticle,
#[serde(rename = "minecraft:resource")]
MinecraftResource { registry: ResourceLocation },
#[serde(rename = "minecraft:resource_key")]
MinecraftResourceKey { registry: ResourceLocation },
#[serde(rename = "minecraft:resource_location")]
MinecraftResourceLocation,
#[serde(rename = "minecraft:resource_or_tag_key")]
MinecraftResourceOrTagKey { registry: ResourceLocation },
#[serde(rename = "minecraft:resource_or_tag")]
MinecraftResourceOrTag { registry: ResourceLocation },
#[serde(rename = "minecraft:rotation")]
MinecraftRotation,
#[serde(rename = "minecraft:score_holder")]
MinecraftScoreHolder { amount: MinecraftAmount },
#[serde(rename = "minecraft:scoreboard_slot")]
MinecraftScoreboardSlot,
#[serde(rename = "minecraft:swizzle")]
MinecraftSwizzle,
#[serde(rename = "minecraft:team")]
MinecraftTeam,
#[serde(rename = "minecraft:template_mirror")]
MinecraftTemplateMirror,
#[serde(rename = "minecraft:template_rotation")]
MinecraftTemplateRotation,
#[serde(rename = "minecraft:time")]
MinecraftTime { min: i32 },
#[serde(rename = "minecraft:uuid")]
MinecraftUuid,
#[serde(rename = "minecraft:vec2")]
MinecraftVec2,
#[serde(rename = "minecraft:vec3")]
MinecraftVec3,
#[serde(other)]
Unknown,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct BrigadierDoubleProperties {
pub min: Option<f64>,
pub max: Option<f64>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct BrigadierFloatProperties {
pub min: Option<f32>,
pub max: Option<f32>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct BrigadierIntegerProperties {
pub min: Option<i32>,
pub max: Option<i32>,
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum MinecraftEntityType {
Players,
Entities,
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum MinecraftAmount {
Single,
Multiple,
}
impl ArgumentParser {
fn name(&self) -> Option<String> {
let a = serde_json::to_value(self).ok()?;
a.as_object()?.get("parser")?.as_str().map(String::from)
}
pub fn parse<'l>(&self, s: &'l str) -> Result<(Argument<'l>, usize), String> {
fn parse_argument<'l, A: ArgumentValue<'l>>(
string: &'l str,
argument_factory: impl Fn(A) -> Argument<'l>,
) -> Result<(Argument<'l>, usize), String> {
Ok(A::parse(string)?.map0(argument_factory))
}
type A<'l> = Argument<'l>;
match self {
Self::BrigadierDouble(..) => Ok(brigadier::parse_double(s)?.map0(A::BrigadierDouble)),
Self::BrigadierInteger(..) => {
Ok(brigadier::parse_integer(s)?.map0(A::BrigadierInteger))
}
Self::BrigadierString { type_ } => {
Ok(brigadier::parse_string(s, *type_)?.map0(A::BrigadierString))
}
Self::MinecraftBlockPos => parse_argument(s, A::MinecraftBlockPos),
Self::MinecraftBlockPredicate => parse_argument(s, A::MinecraftBlockPredicate),
Self::MinecraftDimension => parse_argument(s, A::MinecraftDimension),
Self::MinecraftEntity { .. } => parse_argument(s, A::MinecraftEntity),
Self::MinecraftEntityAnchor => parse_argument(s, A::MinecraftEntityAnchor),
Self::MinecraftFunction => parse_argument(s, A::MinecraftFunction),
Self::MinecraftIntRange => parse_argument(s, A::MinecraftIntRange),
Self::MinecraftHeightmap => parse_argument(s, A::MinecraftHeightmap),
Self::MinecraftMessage => parse_argument(s, A::MinecraftMessage),
Self::MinecraftNbtPath => parse_argument(s, A::MinecraftNbtPath),
Self::MinecraftObjective => parse_argument(s, A::MinecraftObjective),
Self::MinecraftObjectiveCriteria => parse_argument(s, A::MinecraftObjectiveCriteria),
Self::MinecraftOperation => parse_argument(s, A::MinecraftOperation),
Self::MinecraftResource { .. } => parse_argument(s, A::MinecraftResource),
Self::MinecraftResourceLocation => parse_argument(s, A::MinecraftResourceLocation),
Self::MinecraftResourceOrTag { .. } => parse_argument(s, A::MinecraftResourceOrTag),
Self::MinecraftRotation => parse_argument(s, A::MinecraftRotation),
Self::MinecraftScoreHolder { .. } => parse_argument(s, A::MinecraftScoreHolder),
Self::MinecraftScoreboardSlot => parse_argument(s, A::MinecraftScoreboardSlot),
Self::MinecraftSwizzle => parse_argument(s, A::MinecraftSwizzle),
Self::MinecraftTime { .. } => parse_argument(s, A::MinecraftTime),
Self::MinecraftTeam => parse_argument(s, A::MinecraftTeam),
Self::MinecraftVec3 => parse_argument(s, A::MinecraftVec3),
Self::Unknown => Ok(parse_unknown(s)?.map0(A::Unknown)),
_ => Err(format!(
"Unsupported argument type: {}",
self.name().unwrap_or_default()
)),
}
}
}
fn parse_unknown(string: &str) -> Result<(&str, usize), String> {
let len = string.find(' ').unwrap_or(string.len());
Ok((&string[..len], len))
}