minecraft_net/fields/
slot.rs

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    // TODO: verify that this is true.
180    // The wiki says something about "Only present if Has cooldown group is true" but doesn't mention "Has Cooldown group" anywhere else.
181    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}
294// TODO: The wiki says that these are all Optional, but not when they are present.
295Field!(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>, // TODO: verify that this is indeed a PrefixedArray. The wiki says that it's an Array
377    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});