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}