forked from Pumpkin-MC/Pumpkin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.rs
178 lines (146 loc) · 5.67 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use pumpkin_data::item::Item;
use pumpkin_data::tag::{RegistryKey, get_tag_values};
use pumpkin_nbt::compound::NbtCompound;
mod categories;
#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
/// Item Rarity
pub enum Rarity {
Common,
UnCommon,
Rare,
Epic,
}
#[derive(Clone, Debug)]
pub struct ItemStack {
pub item_count: u8,
// TODO: Should this be a ref? all of our items are const
pub item: Item,
}
impl PartialEq for ItemStack {
fn eq(&self, other: &Self) -> bool {
self.item.id == other.item.id
}
}
impl ItemStack {
pub fn new(item_count: u8, item: Item) -> Self {
Self { item_count, item }
}
pub fn damage_item(&mut self) {
let components = &mut self.item.components;
if let (Some(_damage), Some(_max_damage)) = (components.damage, components.max_damage) {
if _max_damage == 0 {
return;
}
// TODO: we probably have to consider the unbreakable enchantment here
if _damage >= _max_damage {
return;
}
components.damage = Some(_damage + 1);
}
}
pub fn is_broken(&self) -> bool {
let components = self.item.components;
// TODO: we probably have to consider the unbreakable enchantment here
if let (Some(_damage), Some(_max_damage)) = (components.damage, components.max_damage) {
return _max_damage > 0 && _damage >= _max_damage;
}
false
}
/// Determines the mining speed for a block based on tool rules.
/// Direct matches return immediately, tagged blocks are checked separately.
/// If no match is found, returns the tool's default mining speed or `1.0`.
pub fn get_speed(&self, block: &str) -> f32 {
// No tool? Use default speed
let Some(tool) = &self.item.components.tool else {
return 1.0;
};
for rule in tool.rules {
// Skip if speed is not set
let Some(speed) = rule.speed else {
continue;
};
for entry in rule.blocks {
if entry.eq(&block) {
return speed;
}
if entry.starts_with('#') {
// Check if block is in the tag group
if let Some(blocks) =
get_tag_values(RegistryKey::Block, entry.strip_prefix('#').unwrap())
{
if blocks.iter().any(|s| *s == block) {
return speed;
}
}
}
}
}
// Return default mining speed if no match is found
tool.default_mining_speed.unwrap_or(1.0)
}
/// Determines if a tool is valid for block drops based on tool rules.
/// Direct matches return immediately, while tagged blocks are checked separately.
pub fn is_correct_for_drops(&self, block: &str) -> bool {
// Return false if no tool component exists
let Some(tool) = &self.item.components.tool else {
return false;
};
for rule in tool.rules {
// Skip rules without a drop condition
let Some(correct_for_drops) = rule.correct_for_drops else {
continue;
};
for entry in rule.blocks {
if entry.eq(&block) {
return correct_for_drops;
}
if entry.starts_with('#') {
// Check if block exists within the tag group
if let Some(blocks) =
get_tag_values(RegistryKey::Block, entry.strip_prefix('#').unwrap())
{
if blocks.iter().any(|s| *s == block) {
return correct_for_drops;
}
}
}
}
}
false
}
pub fn write_item_stack(&self, compound: &mut NbtCompound) {
// Minecraft 1.21.4 uses "id" as string with namespaced ID (minecraft:diamond_sword)
compound.put_string("id", format!("minecraft:{}", self.item.registry_key));
compound.put_int("count", self.item_count as i32);
// Create a tag compound for additional data
let mut tag = NbtCompound::new();
// TODO: Store custom data like enchantments, display name, etc.
if let Some(damage) = self.item.components.damage {
tag.put_int("damage", damage as i32);
}
if let Some(max_damage) = self.item.components.max_damage {
tag.put_int("max_damage", max_damage as i32);
}
compound.put_component("components", tag);
}
pub fn read_item_stack(compound: &NbtCompound) -> Option<Self> {
// Get ID, which is a string like "minecraft:diamond_sword"
let full_id = compound.get_string("id")?;
// Remove the "minecraft:" prefix if present
let registry_key = full_id.strip_prefix("minecraft:").unwrap_or(full_id);
// Try to get item by registry key
let mut item = Item::from_registry_key(registry_key)?.clone();
// TODO: Process additional components like damage, enchantments, etc.
if let Some(_tag) = compound.get_compound("components") {
if let Some(_damage) = _tag.get_int("damage") {
item.components.damage = Some(_damage as u16);
}
if let Some(_max_damage) = _tag.get_int("max_damage") {
item.components.max_damage = Some(_max_damage as u16);
}
}
let count = compound.get_int("count")? as u8;
Some(Self::new(count, item))
}
}