1use crate::fields::block_predicate::BlockPredicate;
2use crate::fields::general::{IDSet, IdOr};
3use crate::fields::types::*;
4use crate::fields::{encode_bool, encode_identifier, encode_prefixed_array, encode_string, encode_var_int};
5use crate::PacketReader;
6use crate::{Field, Result};
7use minecraft_net_proc::{Field, Field_old, VarIntEnum};
8use std::fmt::Debug;
9
10#[derive(Debug, Clone)]
11pub struct Slot {
12 pub item_count: VarInt,
13 pub data: Option<SlotData>,
14}
15impl Field for Slot {
16 fn to_bytes(&self) -> Vec<u8> {
17 let mut res = encode_var_int(self.item_count);
18 if self.item_count > 0 {
19 res.append(&mut self.data.clone().expect("Slot item count bigger than 0 but no data was provided.").to_bytes());
20 }
21 res
22 }
23
24 fn from_reader(reader: &mut PacketReader) -> Result<Self> {
25 let count = reader.read_var_int()?;
26 if count > 0 {
27 Ok(Self {
28 item_count: count,
29 data: Some(SlotData::from_reader(reader)?),
30 })
31 } else {
32 Ok(Self {
33 item_count: count,
34 data: None,
35 })
36 }
37 }
38}
39#[derive(Debug, Clone, Field_old)]
40pub struct SlotData {
41 pub item_id: VarInt,
42 pub number_of_components_to_add: VarInt,
43 pub number_of_components_to_remove: VarInt,
44 #[len = "number_of_components_to_add"]
45 pub components_to_add: Vec<Component>,
46 #[len = "number_of_components_to_remove"]
47 pub components_to_remove: Vec<VarInt>,
48}
49VarIntEnum!(Component, {
50 CustomData: NBT,
51 MaxStackSize: VarInt,
52 MaxDamage: VarInt,
53 Damage: VarInt,
54 Unbreakable: bool,
55 CustomName: String,
56 ItemName: String,
57 ItemModel: Identifier,
58 Lore: PrefixedArray<String>,
59 Rarity: VarInt,
60 Enchantments: OptionalTooltip<PrefixedArray<Enchantment>>,
61 CanPlaceOn: OptionalTooltip<PrefixedArray<BlockPredicate>>,
62 CanBreak: OptionalTooltip<PrefixedArray<BlockPredicate>>,
63 AttributeModifiers: OptionalTooltip<PrefixedArray<AttributeModifier>>,
64 CustomModelData: CustomModelData,
65 HideAdditionalTooltip,
66 HideTooltip,
67 RepairCost: VarInt,
68 CreativeSlotLock,
69 EnchantmentGlintOverride: bool,
70 IntangibleProjectile: NBT,
71 Food: Food,
72 Consumable: Consumable,
73 UseRemainder: Slot,
74 UseCooldown: UseCooldown,
75 DamageResistant: Identifier,
76 Tool: Tool,
77 Enchantable: VarInt,
78 Equippable: Equippable,
79 Reparable: IDSet,
80 Glider,
81 TooltipStyle: Identifier,
82 DeathProtection: PrefixedArray<ConsumeEffect>,
83 StoredEnchantments: OptionalTooltip<StoredEnchantment>,
84 DyedColor: DyedColor,
85 MapColor: Int,
86 MapId: VarInt,
87 MapDecorations: NBT,
88 MapPostProcessing: VarInt,
89 ChargedProjectiles: PrefixedArray<Slot>,
90 BundleContents: PrefixedArray<Slot>,
91 PotionContents: PotionContents,
92 SuspiciousStewEffects: PrefixedArray<SuspiciousStewEffect>,
93 WritableBookContent: WritableBookContent,
94 WrittenBookContent: WrittenBookContent,
95 Trim: Trim,
96 DebugStickState: NBT,
97 EntityData: NBT,
98 BucketEntityData: NBT,
99 BlockEntityData: NBT,
100 Instrument: IdOr<Instrument>,
101 OminousBottleAmplifier: VarInt,
102 JukeboxPlayable: JukeboxPlayable,
103 Recipes: NBT,
104 LodestoneTracker: LodestoneTracker,
105 FireworkExplosion: FireworkExplosion,
106 Profile: Profile,
107 NoteBlockSound: Identifier,
108 BannerPatterns: PrefixedArray<BannerPattern>,
109 BaseColor: DyeColor,
110 PotDecorations: PrefixedArray<VarInt>,
111 Container: PrefixedArray<Slot>,
112 BlockState: PrefixedArray<BlockState>,
113 Bees: PrefixedArray<Bee>,
114 Lock: NBT,
115 ContainerLoot: NBT,
116 });
117#[derive(Debug, Clone)]
118pub struct OptionalTooltip<T: Debug + Clone> {
119 pub value: T,
120 pub show_tooltip: bool,
121}
122impl<T: Debug + Clone + Field> Field for OptionalTooltip<T> {
123 fn to_bytes(&self) -> Vec<u8> {
124 let mut res = self.value.to_bytes();
125 res.append(&mut encode_bool(self.show_tooltip));
126 res
127 }
128 fn from_reader(reader: &mut PacketReader) -> Result<Self> {
129 Ok(Self {
130 value: T::from_reader(reader)?,
131 show_tooltip: reader.read_bool()?,
132 })
133 }
134}
135impl<T: Debug + Clone + Field> Field for OptionalTooltip<PrefixedArray<T>> {
136 fn to_bytes(&self) -> Vec<u8> {
137 let mut res = encode_prefixed_array(&self.value);
138 res.append(&mut encode_bool(self.show_tooltip));
139 res
140 }
141 fn from_reader(reader: &mut PacketReader) -> Result<Self> {
142 Ok(Self {
143 value: reader.read_prefixed_array()?,
144 show_tooltip: reader.read_bool()?,
145 })
146 }
147}
148Field!(Enchantment, {
149 pub type_id: VarInt,
150 pub level: VarInt,
151});
152Field!(AttributeModifier, {
153 attribute_id: VarInt,
154 modifier_id: Identifier,
155 value: Double,
156 operation: VarInt,
157 slot: VarInt,
158 });
159Field!(CustomModelData, {
160 floats: PrefixedArray<Float>,
161 flags: PrefixedArray<bool>,
162 strings: PrefixedArray<String>,
163 colors: PrefixedArray<Int>,
164 });
165Field!(Food, {
166 pub nutrition: VarInt,
167 pub saturation_modifier: Float,
168 pub can_always_eat: bool,
169});
170Field!(Consumable, {
171 consume_seconds: Float,
172 animation: VarInt,
173 sound: IdOr<SoundEvent>,
174 has_consume_particles: bool,
175 effects: PrefixedArray<ConsumeEffect>,
176});
177Field!(UseCooldown, {
178 seconds: Float,
179 cooldown_group: PrefixedOptional<Identifier>
182});
183Field!(Tool, {
184 rule: PrefixedArray<ToolRule>
185 default_mining_speed: Float,
186 damage_per_block: VarInt,
187});
188Field!(ToolRule, {
189 pub blocks: IDSet,
190 pub speed: PrefixedOptional<Float>,
191 pub correct_drop_for_blocks: PrefixedOptional<bool>,
192});
193Field!(Equippable, {
194 slot: VarInt,
195 equip_sound: IdOr<SoundEvent>,
196 model: PrefixedOptional<Identifier>,
197 camera_overlay: PrefixedOptional<Identifier>,
198 allowed_entities: PrefixedOptional<IDSet>,
199 dispensable: bool,
200 swappable: bool,
201 damage_on_hurt: bool,
202});
203Field!(StoredEnchantment, {
204 pub type_id: VarInt,
205 pub level: VarInt,
206});
207Field!(DyedColor, {
208 pub color: Int,
209 pub show_in_tooltip: bool,
210});
211Field!(PotionContents, {
212 pub potion_id: PrefixedOptional<VarInt>,
213 pub custom_color: PrefixedOptional<Int>,
214 pub custom_effects: PrefixedArray<PotionEffect>,
215 pub custom_name: String,
216});
217Field!(SuspiciousStewEffect, {
218 pub type_id: VarInt,
219 pub duration: VarInt,
220});
221Field!(WritableBookContent, {
222 pub raw_content: String,
223 pub filtered_content: PrefixedOptional<String>,
224});
225Field!(WrittenBookContent, {
226 pub raw_title: String,
227 pub filtered_title: PrefixedOptional<String>,
228 pub author: String,
229 pub generation: VarInt,
230 pub pages: PrefixedArray<WritableBookContent>,
231 pub resolved: bool,
232});
233Field!(Trim, {
234 pub trim_material: IdOr<TrimMaterial>,
235 pub trim_pattern: IdOr<TrimPattern>,
236 pub show_in_tooltip: bool
237});
238Field!(TrimMaterial, {
239 asset_name: String,
240 ingredient: VarInt,
241 item_model_index: Float,
242 overrides: PrefixedArray<TrimMaterialOverride>,
243 description: TextComponent,
244});
245Field!(TrimMaterialOverride, {
246 armor_material_type: VarInt,
247 overriden_asset_name: String,
248});
249Field!(TrimPattern, {
250 asset_name: String,
251 template_item: VarInt,
252 description: TextComponent,
253 decal: bool,
254});
255#[derive(Clone, Debug)]
256pub struct JukeboxPlayable {
257 pub direct_mode: bool,
258 pub jukebox_song_name: Option<Identifier>,
259 pub jukebox_song: Option<IdOr<JukeboxSong>>,
260 pub show_in_tooltip: bool,
261}
262impl Field for JukeboxPlayable {
263 fn to_bytes(&self) -> Vec<u8> {
264 encode_bool(self.direct_mode).into_iter()
265 .chain(
266 if self.direct_mode {
267 self.jukebox_song.clone().expect("Direct mode set, but Jukebox Song is None").to_bytes()
268 } else {
269 encode_identifier(self.jukebox_song_name.clone().expect("Direct mode not set, but Jukebox Song name is Non"))
270 })
271 .chain(encode_bool(self.show_in_tooltip))
272 .collect::<Vec<u8>>()
273 }
274
275 fn from_reader(reader: &mut PacketReader) -> Result<Self> {
276 let direct_mode = reader.read_bool()?;
277 if direct_mode {
278 Ok(Self {
279 direct_mode,
280 jukebox_song: Some(reader.read()?),
281 jukebox_song_name: None,
282 show_in_tooltip: reader.read_bool()?,
283 })
284 } else {
285 Ok(Self {
286 direct_mode,
287 jukebox_song: None,
288 jukebox_song_name: Some(reader.read_identifier()?),
289 show_in_tooltip: reader.read_bool()?,
290 })
291 }
292 }
293}
294Field!(JukeboxSong, {
296 sound_event: SoundEvent,
297 description: TextComponent,
298 duration: Float,
299 output: VarInt,
300});
301Field!(LodestoneTracker, {
302 pub has_global_position: bool,
303 pub dimension: Identifier,
304 pub position: Position,
305 pub tracked: bool,
306});
307Field!(Fireworks, {
308 pub flight_duration: VarInt,
309 pub explosions: PrefixedArray<FireworkExplosion>,
310});
311Field!(Profile, {
312 pub name: PrefixedOptional<String>,
313 pub uuid: PrefixedOptional<UUID>,
314 pub property: PrefixedArray<ProfileProperty>
315});
316Field!(ProfileProperty, {
317 pub name: String,
318 pub value: String,
319 pub signature: PrefixedOptional<String>,
320});
321#[derive(Clone, Debug)]
322pub struct BannerPattern {
323 pub pattern_type: VarInt,
324 pub asset_id: Option<Identifier>,
325 pub translation_key: Option<String>,
326 pub color: DyeColor,
327}
328impl Field for BannerPattern {
329 fn to_bytes(&self) -> Vec<u8> {
330 let mut res = encode_var_int(self.pattern_type);
331 if self.pattern_type == 0 {
332 res = res.into_iter().chain(encode_identifier(self.asset_id.clone().expect("pattern_type is 0, but asset_id is None")))
333 .chain(encode_string(self.translation_key.clone().expect("pattern_type is 0, but translation_key is None")))
334 .collect();
335 }
336 res.into_iter().chain(self.color.clone().to_bytes()).collect()
337 }
338
339 fn from_reader(reader: &mut PacketReader) -> Result<Self> {
340 let pattern_type = reader.read_var_int()?;
341 if pattern_type == 0 {
342 Ok(Self {
343 pattern_type,
344 asset_id: Some(reader.read_identifier()?),
345 translation_key: Some(reader.read_string()?),
346 color: reader.read()?
347 })
348 } else {
349 Ok(Self {
350 pattern_type,
351 asset_id: None,
352 translation_key: None,
353 color: reader.read()?
354 })
355 }
356 }
357}
358Field!(BlockState, {
359 pub name: String,
360 pub value: String,
361});
362Field!(Bee, {
363 pub entity_data: NBT,
364 pub ticks_in_hive: VarInt,
365 pub min_ticks_in_hive: VarInt,
366});
367
368VarIntEnum!(ConsumeEffect, {
369 ApplyEffects: ApplyEffects
370 RemoveEffects: IDSet,
371 ClearAllEffects,
372 TeleportRandomly: Float,
373 PlaySound: SoundEvent
374});
375Field!(ApplyEffects, {
376 effects: PrefixedArray<PotionEffect>, probability: Float,
378});
379Field!(PotionEffect, {
380 type_id: VarInt,
381 details: PotionEffectDetail,
382});
383Field!(PotionEffectDetail, {
384 amplifier: VarInt,
385 duration: VarInt,
386 ambient: bool,
387 show_particles: bool,
388 show_icon: bool,
389 hidden_effect: PrefixedOptional<Box<PotionEffectDetail>>
390});
391Field!(SoundEvent, {
392 sound_name: Identifier,
393 fixed_range: PrefixedOptional<Float>
394});
395Field!(Instrument, {
396 sound_event: IdOr<SoundEvent>,
397 use_duration: Float,
398 range: Float,
399 description: TextComponent,
400});
401Field!(FireworkExplosion, {
402 shape: FireworkExplosionShape,
403 colors: PrefixedArray<Int>,
404 fade_colors: PrefixedArray<Int>,
405 has_trail: bool,
406 has_twinkle: bool,
407});
408VarIntEnum!(FireworkExplosionShape, {
409 SmallBall,
410 LargeBall,
411 Star,
412 Creeper,
413 Burst,
414});
415VarIntEnum!(DyeColor, {
416 White,
417 Orange,
418 Magenta,
419 LightBlue,
420 Yellow,
421 Lime,
422 Pink,
423 Gray,
424 LightGray,
425 Cyan,
426 Purple,
427 Blue,
428 Brown,
429 Green,
430 Red,
431 Black,
432});