minecraft_command_types/
item.rs

1use crate::resource_location::ResourceLocation;
2use crate::snbt::SNBT;
3use minecraft_command_types_derive::HasMacro;
4use std::fmt::{Display, Formatter};
5
6#[derive(Debug, Clone, Eq, PartialEq, Hash, HasMacro)]
7pub enum ItemTest {
8    Component(ResourceLocation),
9    ComponentMatches(ResourceLocation, SNBT),
10    Predicate(ResourceLocation, SNBT),
11}
12
13impl Display for ItemTest {
14    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15        match self {
16            ItemTest::Component(id) => id.fmt(f),
17            ItemTest::ComponentMatches(id, value) => write!(f, "{}={}", id, value),
18            ItemTest::Predicate(id, value) => write!(f, "{}~{}", id, value),
19        }
20    }
21}
22
23#[derive(Debug, Clone, Eq, PartialEq, Hash, HasMacro)]
24pub enum ItemType {
25    ResourceLocation(ResourceLocation),
26    Wildcard,
27}
28
29impl Display for ItemType {
30    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31        match self {
32            ItemType::ResourceLocation(resource_location) => resource_location.fmt(f),
33            ItemType::Wildcard => f.write_str("*"),
34        }
35    }
36}
37
38#[derive(Debug, Clone, Eq, PartialEq, Hash, HasMacro)]
39pub struct OrGroup(pub Vec<(bool, ItemTest)>);
40
41impl Display for OrGroup {
42    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43        let parts: Vec<String> = self
44            .0
45            .iter()
46            .map(|(negated, test)| {
47                if *negated {
48                    format!("!{}", test)
49                } else {
50                    test.to_string()
51                }
52            })
53            .collect();
54        write!(f, "{}", parts.join("|"))
55    }
56}
57
58#[derive(Debug, Clone, Eq, PartialEq, Hash, HasMacro)]
59pub struct ItemPredicate {
60    pub id: ItemType,
61    pub tests: Vec<OrGroup>,
62}
63
64impl Display for ItemPredicate {
65    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
66        self.id.fmt(f)?;
67
68        if self.tests.is_empty() {
69            return Ok(());
70        }
71
72        write!(f, "[")?;
73
74        let parts: Vec<String> = self.tests.iter().map(|g| g.to_string()).collect();
75        write!(f, "{}]", parts.join(","))
76    }
77}
78
79impl ItemPredicate {
80    pub fn new(id: ItemType) -> Self {
81        Self {
82            id,
83            tests: Vec::new(),
84        }
85    }
86
87    pub fn with_test_group(mut self, group: OrGroup) -> Self {
88        self.tests.push(group);
89        self
90    }
91
92    pub fn with_test(self, negated: bool, test: ItemTest) -> Self {
93        let group = OrGroup(vec![(negated, test)]);
94        self.with_test_group(group)
95    }
96}
97
98#[derive(Debug, Clone, Eq, PartialEq, Hash, HasMacro)]
99pub enum ItemComponent {
100    KeyValue(ResourceLocation, SNBT),
101    Remove(ResourceLocation),
102}
103
104impl Display for ItemComponent {
105    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106        match self {
107            ItemComponent::KeyValue(component, value) => {
108                write!(f, "{}={}", component, value)
109            }
110            ItemComponent::Remove(component) => write!(f, "!{}", component),
111        }
112    }
113}
114
115#[derive(Debug, Clone, Eq, PartialEq, Hash, HasMacro)]
116pub struct ItemStack {
117    pub id: ItemType,
118    pub components: Vec<ItemComponent>,
119}
120
121impl Display for ItemStack {
122    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123        self.id.fmt(f)?;
124
125        if !self.components.is_empty() {
126            write!(f, "[")?;
127            let mut first = true;
128
129            for component in &self.components {
130                if !first {
131                    write!(f, ", ")?;
132                }
133
134                write!(f, "{}", component)?;
135
136                first = false;
137            }
138
139            write!(f, "]")?;
140        }
141
142        Ok(())
143    }
144}