mcproto_rs/
v1_15_2.rs

1use crate::{types::*, uuid::*, *};
2use alloc::{string::{String, ToString}, vec::Vec, borrow::ToOwned, boxed::Box};
3use alloc::fmt;
4use fmt::Debug;
5
6#[cfg(all(test, feature = "std"))]
7use crate::protocol::TestRandom;
8
9define_protocol!(578, Packet578, RawPacket578, RawPacket578Body, Packet578Kind => {
10    // handshaking
11    Handshake, 0x00, Handshaking, ServerBound => HandshakeSpec {
12        version: VarInt,
13        server_address: String,
14        server_port: u16,
15        next_state: HandshakeNextState
16    },
17
18    // status
19    StatusRequest, 0x00, Status, ServerBound => StatusRequestSpec {},
20    StatusPing, 0x01, Status, ServerBound => StatusPingSpec {
21        payload: i64
22    },
23    StatusResponse, 0x00, Status, ClientBound => StatusResponseSpec {
24        response: super::status::StatusSpec
25    },
26    StatusPong, 0x01, Status, ClientBound => StatusPongSpec {
27        payload: i64
28    },
29
30    // login
31    LoginDisconnect, 0x00, Login, ClientBound => LoginDisconnectSpec {
32        message: Chat
33    },
34    LoginEncryptionRequest, 0x01, Login, ClientBound => LoginEncryptionRequestSpec {
35        server_id: String,
36        public_key: CountedArray<u8, VarInt>,
37        verify_token: CountedArray<u8, VarInt>
38    },
39    LoginSuccess, 0x02, Login, ClientBound => LoginSuccessSpec {
40        uuid_string: String,
41        username: String
42    },
43    LoginSetCompression, 0x03, Login, ClientBound => LoginSetCompressionSpec {
44        threshold: VarInt
45    },
46    LoginPluginRequest, 0x04, Login, ClientBound => LoginPluginRequestSpec {
47        message_id: VarInt,
48        channel: String,
49        data: RemainingBytes
50    },
51    LoginStart, 0x00, Login, ServerBound => LoginStartSpec {
52        name: String
53    },
54    LoginEncryptionResponse, 0x01, Login, ServerBound => LoginEncryptionResponseSpec {
55        shared_secret: CountedArray<u8, VarInt>,
56        verify_token: CountedArray<u8, VarInt>
57    },
58    LoginPluginResponse, 0x02, Login, ServerBound => LoginPluginResponseSpec {
59        message_id: VarInt,
60        successful: bool,
61        data: RemainingBytes
62    },
63
64    // play
65    // client bound
66    PlaySpawnEntity, 0x00, Play, ClientBound => PlaySpawnEntitySpec {
67        entity_id: VarInt,
68        object_uuid: UUID4,
69        entity_type: VarInt,
70        position: Vec3<f64>,
71        pitch: Angle,
72        yaw: Angle,
73        data: i32,
74        velocity: Vec3<i16>
75    },
76    PlaySpawnExperienceOrb, 0x01, Play, ClientBound => PlaySpawnExperienceOrbSpec {
77        entity_id: VarInt,
78        position: Vec3<f64>,
79        count: i16
80    },
81    PlaySpawnWeatherEntity, 0x02, Play, ClientBound => PlaySpawnWeatherEntitySpec {
82        entity_id: VarInt,
83        entity_type: u8,
84        position: Vec3<f64>
85    },
86    PlaySpawnLivingEntity, 0x03, Play, ClientBound => PlaySpawnLivingEntitySpec {
87        entity_id: VarInt,
88        entity_uuid: UUID4,
89        entity_type: VarInt,
90        location: EntityLocation<f64, Angle>,
91        head_pitch: Angle,
92        velocity: Vec3<i16>
93    },
94    PlaySpawnPainting, 0x04, Play, ClientBound => PlaySpawnPaintingSpec {
95        entity_id: VarInt,
96        entity_uuid: UUID4,
97        motive: VarInt,
98        location: IntPosition,
99        direction: CardinalDirection
100    },
101    PlaySpawnPlayer, 0x05, Play, ClientBound => PlaySpawnPlayerSpec {
102        entity_id: VarInt,
103        uuid: UUID4,
104        location: EntityLocation<f64, Angle>
105    },
106    PlayEntityAnimation, 0x06, Play, ClientBound => PlayEntityAnimationSpec {
107        entity_id: VarInt,
108        animation: EntityAnimationKind
109    },
110    PlayStatistics, 0x07, Play, ClientBound => PlayStatisticsSpec {
111        entries: CountedArray<Statistic, VarInt>
112    },
113    PlayAcknowledgePlayerDigging, 0x08, Play, ClientBound => PlayAcknowledgePlayerDiggingSpec {
114        location: IntPosition,
115        block: VarInt,
116        status: DiggingStatus,
117        successful: bool
118    },
119    PlayBlockBreakAnimation, 0x09, Play, ClientBound => PlayBlockBreakAnimationSpec {
120        entity_id: VarInt,
121        location: IntPosition,
122        destroy_stage: i8
123    },
124    PlayBlockEntityData, 0x0A, Play, ClientBound => PlayBlockEntityDataSpec {
125        location: IntPosition,
126        action: BlockEntityDataAction,
127        nbt_data: NamedNbtTag
128    },
129    PlayBlockAction, 0x0B, Play, ClientBound => PlayBlockActionSpec {
130        location: IntPosition,
131        action_id: u8,
132        action_payload: u8,
133        block_type: VarInt
134    },
135    PlayBlockChange, 0x0C, Play, ClientBound => PlayBlockChangeSpec {
136        location: IntPosition,
137        block_id: VarInt
138    },
139    PlayBossBar, 0x0D, Play, ClientBound => PlayBossBarSpec {
140        uuid: UUID4,
141        action: BossBarAction
142    },
143    PlayServerDifficulty, 0x0E, Play, ClientBound => PlayServerDifficultySpec {
144        difficulty: Difficulty,
145        locked: bool
146    },
147    PlayServerChatMessage, 0x0F, Play, ClientBound => PlayServerChatMessageSpec {
148        message: Chat,
149        position: ChatPosition
150    },
151    PlayMultiBlockChange, 0x10, Play, ClientBound => PlayMultiBlockChangeSpec {
152        chunk: ChunkPosition<i32>,
153        changes: CountedArray<MultiBlockChangeRecord, VarInt>
154    },
155    PlayTabComplete, 0x11, Play, ClientBound => PlayTabCompleteSpec {
156        id: VarInt,
157        start: VarInt,
158        length: VarInt,
159        matches: CountedArray<TabCompleteMatch, VarInt>
160    },
161    PlayDeclareCommands, 0x12, Play, ClientBound => PlayDeclareCommandsSpec {
162        nodes: CountedArray<CommandNodeSpec, VarInt>,
163        root_index: VarInt
164    },
165    PlayServerWindowConfirmation, 0x13, Play, ClientBound => PlayServerWindowConfirmationSpec {
166        window_id: u8,
167        action_number: i16,
168        accepted: bool
169    },
170    PlayServerCloseWindow, 0x14, Play, ClientBound => PlayServerCloseWindowSpec {
171        window_id: u8
172    },
173    PlayWindowItems, 0x15, Play, ClientBound => PlayWindowItemsSpec {
174        window_id: u8,
175        slots: CountedArray<Slot, i16>
176    },
177    PlayWindowProperty, 0x16, Play, ClientBound => PlayWindowPropertySpec {
178        window_id: u8,
179        property: i16,
180        value: i16
181    },
182    PlaySetSlot, 0x17, Play, ClientBound => PlaySetSlotSpec {
183        window_id: u8,
184        slow: i16,
185        slot_data: Slot
186    },
187    PlaySetCooldown, 0x18, Play, ClientBound => PlaySetCooldownSpec {
188        item_id: VarInt,
189        cooldown_ticks: VarInt
190    },
191    PlayServerPluginMessage, 0x19, Play, ClientBound => PlayServerPluginMessageSpec {
192        channel: String,
193        data: RemainingBytes
194    },
195    PlayNamedSoundEffect, 0x1A, Play, ClientBound => PlayNamedSoundEffectSpec {
196        sound_name: String,
197        sound_category: SoundCategory,
198        position: Vec3<FixedInt>,
199        volume: f32,
200        pitch: f32
201    },
202    PlayDisconnect, 0x1B, Play, ClientBound => PlayDisconnectSpec {
203        reason: Chat
204    },
205    PlayEntityStatus, 0x1C, Play, ClientBound => PlayEntityStatusSpec {
206        entity_id: i32,
207        raw_status: u8 // todo deal with the gigantic table
208    },
209    PlayExplosion, 0x1D, Play, ClientBound => PlayExplosionSpec {
210        position: Vec3<f32>,
211        strength: f32,
212        records: CountedArray<Vec3<i8>, i32>,
213        player_motion: Vec3<f32>
214    },
215    PlayUnloadChunk, 0x1E, Play, ClientBound => PlayUnloadChunkSpec {
216        position: ChunkPosition<i32>
217    },
218    PlayChangeGameState, 0x1F, Play, ClientBound => PlayChangeGameStateSpec {
219        reason: GameChangeReason
220    },
221    PlayOpenHorseWindow, 0x20, Play, ClientBound => PlayOpenHorseWindowSpec {
222        window_id: u8,
223        number_of_slots: VarInt,
224        entity_id: i32
225    },
226    PlayServerKeepAlive, 0x21, Play, ClientBound => PlayServerKeepAliveSpec {
227        id: i64
228    },
229    PlayChunkData, 0x22, Play, ClientBound => PlayChunkDataWrapper {
230        data: ChunkData
231    },
232    PlayEffect, 0x23, Play, ClientBound => PlayEffectSpec {
233        effect_id: i32,
234        location: IntPosition,
235        data: i32,
236        disable_relative_volume: bool
237    },
238    PlayParticle, 0x24, Play, ClientBound => PlayParticleSpec {
239        particle_id: i32,
240        long_distance: bool,
241        position: Vec3<f64>,
242        offset: Vec3<f32>,
243        particle_data: i32,
244        data: RemainingBytes // todo
245    },
246    PlayUpdateLight, 0x25, Play, ClientBound => PlayUpdateLightSpec {
247        chunk: ChunkPosition<VarInt>,
248        update: LightingUpdateSpec
249    },
250    PlayJoinGame, 0x26, Play, ClientBound => PlayJoinGameSpec {
251        entity_id: i32,
252        gamemode: GameMode,
253        dimension: Dimension,
254        hashed_seed: i64,
255        max_players: u8,
256        level_type: String,
257        view_distance: VarInt,
258        reduced_debug_info: bool,
259        enable_respawn_screen: bool
260    },
261    PlayMapData, 0x27, Play, ClientBound => PlayMapDataSpec {
262        map_id: VarInt,
263        scale: i8,
264        tracking_position: bool,
265        locked: bool,
266        icons: CountedArray<MapIconSpec, VarInt>,
267        columns: MapColumns
268    },
269    PlayTradeList, 0x28, Play, ClientBound => PlayTradeListSpec {
270        window_id: VarInt,
271        trades: CountedArray<TradeSpec, i8>,
272        villager_level: VarInt,
273        experience: VarInt,
274        regular_villager: bool,
275        can_restock: bool
276    },
277    PlayEntityPosition, 0x29, Play, ClientBound => PlayEntityPositionSpec {
278        entity_id: VarInt,
279        delta: Vec3<i16>,
280        on_ground: bool
281    },
282    PlayEntityPositionAndRotation, 0x2A, Play, ClientBound => PlayEntityPositionAndRotationSpec {
283        entity_id: VarInt,
284        delta: EntityLocation<i16, Angle>,
285        on_ground: bool
286    },
287    PlayEntityRotation, 0x2B, Play, ClientBound => PlayEntityRotationSpec {
288        entity_id: VarInt,
289        rotation: EntityRotation<Angle>,
290        on_ground: bool
291    },
292    PlayEntityMovement, 0x2C, Play, ClientBound => PlayEntityMovementSpec {
293        entity_id: VarInt
294    },
295    PlayServerVehicleMove, 0x2D, Play, ClientBound => PlayEntityVehicleMoveSpec {
296        location: EntityLocation<f64, f32>
297    },
298    PlayOpenBook, 0x2E, Play, ClientBound => PlayOpenBookSpec {
299        hand: Hand
300    },
301    PlayOpenWindow, 0x2F, Play, ClientBound => PlayOpenWindowSpec {
302        id: VarInt,
303        kind: WindowType,
304        title: String
305    },
306    PlayOpenSignEditor, 0x30, Play, ClientBound => PlayOpenSignEditorSpec {
307        location: IntPosition
308    },
309    PlayCraftRecipeResponse, 0x31, Play, ClientBound => PlayCraftRecipeResponseSpec {
310        window_id: u8,
311        recipe: String
312    },
313    PlayServerPlayerAbilities, 0x32, Play, ClientBound => PlayServerPlayerAbilitiesSpec {
314        flags: PlayerAbilityFlags,
315        flying_speed: f32,
316        field_of_view_modifier: f32
317    },
318    PlayCombatEvent, 0x33, Play, ClientBound => PlayCombatEventSpec {
319        event: CombatEvent
320    },
321    PlayPlayerInfo, 0x34, Play, ClientBound => PlayPlayerInfoSpec {
322        actions: PlayerInfoActionList
323    },
324    PlayFacePlayer, 0x35, Play, ClientBound => PlayFacePlayerSpec {
325        face_kind: FacePlayerKind,
326        target: Vec3<f64>,
327        entity: Option<FacePlayerEntityTarget>
328    },
329    PlayServerPlayerPositionAndLook, 0x36, Play, ClientBound => PlayServerPlayerPositionAndLookSpec {
330        location: EntityLocation<f64, f32>,
331        flags: PositionAndLookFlags,
332        teleport_id: VarInt
333    },
334    PlayUnlockRecipes, 0x37, Play, ClientBound => PlayUnlockRecipesSpec {
335        action: RecipeUnlockAction,
336        crafting_book_open: bool,
337        crafting_book_active: bool,
338        smelting_book_open: bool,
339        smelting_book_active: bool,
340        recipe_ids: CountedArray<String, VarInt>,
341        other_recipe_ids: RemainingBytes // todo
342    },
343    PlayDestroyEntities, 0x38, Play, ClientBound => PlayDestroyEntitiesSpec {
344        entity_ids: CountedArray<VarInt, VarInt>
345    },
346    PlayRemoveEntityEffect, 0x39, Play, ClientBound => PlayRemoveEntityEffectSpec {
347        entity_id: VarInt,
348        effect: EntityEffectKind
349    },
350    PlayResourcePackSend, 0x3A, Play, ClientBound => PlayResourcePackSendSpec {
351        url: String,
352        hash: String
353    },
354    PlayRespawn, 0x3B, Play, ClientBound => PlayRespawnSpec {
355        dimension: Dimension,
356        hashed_seed: i64,
357        gamemode: GameMode,
358        level_type: String
359    },
360    PlayEntityHeadLook, 0x3C, Play, ClientBound => PlayEntityHeadLookSpec {
361        entity_id: VarInt,
362        head_yaw: Angle
363    },
364    PlaySelectAdvancementTab, 0x3D, Play, ClientBound => PlaySelectAdvancementTabSpec {
365        identifier: Option<String>
366    },
367    PlayWorldBorder, 0x3E, Play, ClientBound => PlayWorldBorderSpec {
368        action: WorldBorderAction
369    },
370    PlayCamera, 0x3F, Play, ClientBound => PlayCameraSpec {
371        camera_id: VarInt
372    },
373    PlayServerHeldItemChange, 0x40, Play, ClientBound => PlayServerHeldItemChangeSpec {
374        slot: i8
375    },
376    PlayUpdateViewPosition, 0x41, Play, ClientBound => PlayUpdateViewPositionSpec {
377        chunk: ChunkPosition<VarInt>
378    },
379    PlayUpdateViewDistance, 0x42, Play, ClientBound => PlayUpdateViewDistanceSpec {
380        view_distance: VarInt
381    },
382    PlayDisplayScoreboard, 0x43, Play, ClientBound => PlayDisplayScoreboardSpec {
383        position: ScoreboardPosition,
384        score_name: String
385    },
386    PlayEntityMetadata, 0x44, Play, ClientBound => PlayEntityMetadataSpec {
387        entity_id: VarInt,
388        metadata: EntityMetadata
389    },
390    PlayAttachEntity, 0x45, Play, ClientBound => PlayAttachEntitySpec {
391        attached_entity_id: i32,
392        holding_entity_id: i32
393    },
394    PlayEntityVelocity, 0x46, Play, ClientBound => PlayEntityVelocitySpec {
395        entity_id: VarInt,
396        velocity: Vec3<i16>
397    },
398    PlayEntityEquipment, 0x47, Play, ClientBound => PlayEntityEquiptmentSpec {
399        entity_id: VarInt,
400        slot: EquipmentSlot,
401        item: Slot
402    },
403    PlaySetExperience, 0x48, Play, ClientBound => PlaySetExperienceSpec {
404        experience_bar: f32,
405        level: VarInt,
406        total_experience: VarInt
407    },
408    PlayUpdatehealth, 0x49, Play, ClientBound => PlayUpdateHealthSpec {
409        health: f32,
410        food: VarInt,
411        saturation: f32
412    },
413    PlayScoreboardObjective, 0x4A, Play, ClientBound => PlayScoreboardObjectiveSpec {
414        objective_name: String,
415        action: ScoreboardObjectiveAction
416    },
417    PlaySetPassengers, 0x4B, Play, ClientBound => PlaySetPassengersSpec {
418        entity_id: VarInt,
419        passenger_entitiy_ids: CountedArray<VarInt, VarInt>
420    },
421    PlayTeams, 0x4C, Play, ClientBound => PlayTeamsSpec {
422        team_name: String,
423        action: TeamAction
424    },
425    PlayUpdateScore, 0x4D, Play, ClientBound => PlayUpdateScoreSpec {
426        entity_name: TeamMember,
427        update: UpdateScoreSpec
428    },
429    PlaySpawnPosition, 0x4E, Play, ClientBound => PlaySpawnPositionSpec {
430        location: IntPosition
431    },
432    PlayTimeUpdate, 0x4F, Play, ClientBound => PlayTimeUpdateSpec {
433        world_age: i64,
434        time_of_day: i64
435    },
436    PlayTitle, 0x50, Play, ClientBound => PlayTitleSpec {
437        action: TitleActionSpec
438    },
439    PlayEntitySoundEffect, 0x51, Play, ClientBound => PlayEntitySoundEffectSpec {
440        sound_id: VarInt,
441        sound_category: SoundCategory,
442        entity_id: VarInt,
443        volume: f32,
444        pitch: f32
445    },
446    PlaySoundEffect, 0x52, Play, ClientBound => PlaySoundEffectSpec {
447        sound_id: VarInt,
448        sound_category: SoundCategory,
449        position: Vec3<FixedInt>,
450        volume: f32,
451        pitch: f32
452    },
453    PlayStopSound, 0x53, Play, ClientBound => PlayStopSoundSpec {
454        spec: StopSoundSpec
455    },
456    PlayerPlayerListHeaderAndFooter, 0x54, Play, ClientBound => PlayPlayerListHeaderAndFooterSpec {
457        header: Chat,
458        footer: Chat
459    },
460    PlayNbtQueryResponse, 0x55, Play, ClientBound => PlayNbtQueryResponseSpec {
461        transaction_id: VarInt,
462        nbt: NamedNbtTag
463    },
464    PlayCollectItem, 0x56, Play, ClientBound => PlayCollectItemSpec {
465        collected_entity_id: VarInt,
466        collector_entity_id: VarInt,
467        pickup_item_count: VarInt
468    },
469    PlayEntityTeleport, 0x57, Play, ClientBound => PlayEntityTeleportSpec {
470        entity_id: VarInt,
471        location: EntityLocation<f64, Angle>,
472        on_ground: bool
473    },
474    PlayAdvancements, 0x58, Play, ClientBound => PlayAdvancementsSpec {
475        reset: bool,
476        mappings: CountedArray<AdvancementMappingEntrySpec, VarInt>,
477        identifiers: CountedArray<String, VarInt>,
478        progress: CountedArray<AdvancementProgressEntrySpec, VarInt>
479    },
480    PlayEntityProperties, 0x59, Play, ClientBound => PlayEntityPropertiesSpec {
481        entity_id: VarInt,
482        properties: CountedArray<EntityPropertySpec, i32>
483    },
484    PlayEntityEffect, 0x5A, Play, ClientBound => PlayEntityEffectSpec {
485        entity_id: VarInt,
486        effect_id: EntityEffectKind,
487        amplifier: i8,
488        duration_ticks: VarInt,
489        flags: EntityEffectFlags
490    },
491    PlayDeclareRecipes, 0x5B, Play, ClientBound => PlayDeclareRecipesSpec {
492        recipes: CountedArray<RecipeSpec, VarInt>
493    },
494    PlayTags, 0x5C, Play, ClientBound => PlayTagsSpec {
495        block_tags: CountedArray<TagSpec, VarInt>,
496        item_tags: CountedArray<TagSpec, VarInt>,
497        fluid_tags: CountedArray<TagSpec, VarInt>,
498        entity_tags: CountedArray<TagSpec, VarInt>
499    },
500
501    // play server bound
502    PlayTeleportConfirm, 0x00, Play, ServerBound => PlayTeleportConfirmSpec {
503        teleport_id: VarInt
504    },
505    PlayQueryBlockNbt, 0x01, Play, ServerBound => PlayQueryBlockNbtSpec {
506        transaction_id: VarInt,
507        location: IntPosition
508    },
509    PlayQueryEntityNbt, 0x0D, Play, ServerBound => PlayQueryEntityNbtSpec {
510        transaction_id: VarInt,
511        entity_id: VarInt
512    },
513    PlaySetDifficulty, 0x02, Play, ServerBound => PlaySetDifficultySpec {
514        new_difficulty: Difficulty
515    },
516    PlayClientChatMessage, 0x03, Play, ServerBound => PlayClientChatMessageSpec {
517        message: String
518    },
519    PlayClientStatus, 0x04, Play, ServerBound => PlayClientStatusSpec {
520        action: ClientStatusAction
521    },
522    PlayClientSettings, 0x05, Play, ServerBound => PlayClientSettingsSpec {
523        locale: String,
524        view_distance: i8,
525        chat_mode: ClientChatMode,
526        chat_colors: bool,
527        displayed_skin_parts: ClientDisplayedSkinParts,
528        main_hand: ClientMainHand
529    },
530    PlayClientTabComplete, 0x06, Play, ServerBound => PlayClientTabCompleteSpec {
531        transaction_id: VarInt,
532        text: String
533    },
534    PlayClientWindowConfirmation, 0x07, Play, ServerBound => PlayClientWindowConfirmationSpec {
535        window_id: i8,
536        action_num: i16,
537        accepted: bool
538    },
539    PlayClickWindowButton, 0x08, Play, ServerBound => PlayClickWindowButtonSpec {
540        window_id: i8,
541        button_id: i8
542    },
543    PlayClickWindow, 0x09, Play, ServerBound => PlayClickWindowSpec {
544        window_id: u8,
545        slot: i16,
546        button: i8,
547        action_number: i16,
548        mode: InventoryOperationMode,
549        clicked_item: Slot
550    },
551    PlayClientCloseWindow, 0x0A, Play, ServerBound => PlayClientCloseWindowSpec {
552        window_id: u8
553    },
554    PlayClientPluginMessage, 0x0B, Play, ServerBound => PlayClientPluginMessageSpec {
555        channel: String,
556        data: RemainingBytes
557    },
558    PlayEditBook, 0x0C, Play, ServerBound => PlayEditBookSpec {
559        new_book: Slot,
560        is_signing: bool,
561        hand: Hand
562    },
563    PlayInteractEntity, 0x0E, Play, ServerBound => PlayInteractEntitySpec {
564        entity_id: VarInt,
565        kind: InteractKind
566    },
567    PlayClientKeepAlive, 0x0F, Play, ServerBound => PlayClientKeepAliveSpec {
568        id: i64
569    },
570    PlayLockDifficulty, 0x10, Play, ServerBound => PlayLockDifficultySpec {
571        locked: bool
572    },
573    PlayPlayerPosition, 0x11, Play, ServerBound => PlayPlayerPositionSpec {
574        feet_position: Vec3<f64>,
575        on_ground: bool
576    },
577    PlayClientPlayerPositionAndRotation, 0x12, Play, ServerBound => PlayClientPlayerPositionAndRotationSpec {
578        feet_location: EntityLocation<f64, f32>,
579        on_ground: bool
580    },
581    PlayPlayerRotation, 0x13, Play, ServerBound => PlayPlayerRotationSpec {
582        rotation: EntityRotation<f32>,
583        on_ground: bool
584    },
585    PlayPlayerMovement, 0x14, Play, ServerBound => PlayPlayerMovementSpec {
586        on_ground: bool
587    },
588    PlayClientVehicleMove, 0x15, Play, ServerBound => PlayClientVehicleMoveSpec {
589        location: EntityLocation<f64, f32>
590    },
591    PlaySteerBoat, 0x16, Play, ServerBound => PlaySteerBoatSpec {
592        left_paddle_turning: bool,
593        right_paddle_turning: bool
594    },
595    PlayPickItem, 0x17, Play, ServerBound => PlayPickItemSpec {
596        slot_idx: VarInt
597    },
598    PlayCraftRecipeRequest, 0x18, Play, ServerBound => PlayCraftRecipeRequestSpec {
599        window_id: i8,
600        recipe: String,
601        make_all: bool
602    },
603    PlayClientPlayerAbilities, 0x19, Play, ServerBound => PlayClientPlayerAbilitiesSpec {
604        flags: ClientPlayerAbilities,
605        flying_speed: f32,
606        walking_speed: f32
607    },
608    PlayPlayerDigging, 0x1A, Play, ServerBound => PlayPlayerDiggingSpec {
609        status: PlayerDiggingStatus,
610        location: IntPosition,
611        face: DiggingFace
612    },
613    PlayEntityAction, 0x1B, Play, ServerBound => PlayEntityActionSpec {
614        entity_id: VarInt,
615        action: EntityActionKind,
616        jump_boot: VarInt
617    },
618    PlaySteerVehicle, 0x1C, Play, ServerBound => PlaySteerVehicleSpec {
619        sideways: f32,
620        forward: f32,
621        flags: SteerVehicleFlags
622    },
623    PlayRecipeBookData, 0x1D, Play, ServerBound => PlayRecipeBookDataSpec {
624        status: RecipeBookStatus
625    },
626    PlayNameItem, 0x1E, Play, ServerBound => PlayNameItemSpec {
627        name: String
628    },
629    PlayResourcePackStatus, 0x1F, Play, ServerBound => PlayResourcePackStatusSpec {
630        status: ResourcePackStatus
631    },
632    PlayAdvancementTab, 0x20, Play, ServerBound => PlayAdvancementTabSpec {
633        action: AdvancementTabAction
634    },
635    PlaySelectTrade, 0x21, Play, ServerBound => PlaySelectTradeSpec {
636        selected_slot: VarInt
637    },
638    PlaySetBeaconEffect, 0x22, Play, ServerBound => PlaySetBeaconEffectSpec {
639        primary_effect: VarInt,
640        secondary_effect: VarInt
641    },
642    PlayClientHeldItemChange, 0x23, Play, ServerBound => PlayClientHeldItemChangeSpec {
643        slot: i16
644    },
645    PlayUpdateCommandBlock, 0x24, Play, ServerBound => PlayUpdateCommandBlockSpec {
646        location: IntPosition,
647        command: String,
648        mode: CommandBlockMode,
649        flags: CommandBlockFlags
650    },
651    PlayUpdateCommandBlockMinecart, 0x25, Play, ServerBound => PlayUpdateCommandBlockMinecartSpec {
652        entity_id: VarInt,
653        command: String,
654        track_output: bool
655    },
656    PlayCreativeInventoryAction, 0x26, Play, ServerBound => PlayCreativeInventoryActionSpec {
657        slot: i16,
658        clicked_item: Slot
659    },
660    PlayUpdateJigsawBlock, 0x27, Play, ServerBound => PlayUpdateJigsawBlockSpec {
661        location: IntPosition,
662        attachment_type: String,
663        target_pool: String,
664        final_state: String
665    },
666    PlayUpdateStructureBlock, 0x28, Play, ServerBound => PlayUpdateStructureBlockSpec {
667        location: IntPosition,
668        action: UpdateStructureBlockAction,
669        mode: UpdateStructureBlockMode,
670        name: String,
671        offset: Vec3<i8>,
672        size: Vec3<i8>,
673        mirror: UpdateStructureBlockMirror,
674        rotation: UpdateStructureBlockRotation,
675        metadata: String,
676        integrity: f32,
677        seed: VarLong,
678        flags: UpdateStructureBlockFlags
679    },
680    PlayUpdateSign, 0x29, Play, ServerBound => PlayUpdateSignSpec {
681        location: IntPosition,
682        line1: String,
683        line2: String,
684        line3: String,
685        line4: String
686    },
687    PlayClientAnimation, 0x2A, Play, ServerBound => PlayClientAnimationSpec {
688        hand: Hand
689    },
690    PlaySpectate, 0x2B, Play, ServerBound => PlaySpectateSpec {
691        target: UUID4
692    },
693    PlayBlockPlacement, 0x2C, Play, ServerBound => PlayBlockPlacementSpec {
694        hand: Hand,
695        location: IntPosition,
696        face: DiggingFace,
697        cursor_position: Vec3<f32>,
698        inside_block: bool
699    },
700    PlayUseItem, 0x2D, Play, ServerBound => PlayUseItemSpec {
701        hand: Hand
702    }
703});
704
705// helper types
706
707// handshake enum
708proto_byte_enum!(HandshakeNextState,
709    0x01 :: Status,
710    0x02 :: Login
711);
712
713proto_byte_enum!(CardinalDirection,
714    0x00 :: South,
715    0x01 :: West,
716    0x02 :: North,
717    0x03:: East
718);
719
720proto_byte_enum!(EntityAnimationKind,
721    0x00 :: SwingMainArm,
722    0x01 :: TakeDamage,
723    0x02 :: LeaveBed,
724    0x03 :: SwingOffHand,
725    0x04 :: CriticalEffect,
726    0x05 :: MagicCriticalEffect
727);
728
729proto_varint_enum!(StatisticCategory,
730    0x00 :: Mined(VarInt),
731    0x01 :: Crafted(VarInt),
732    0x02 :: Used(VarInt),
733    0x03 :: Broken(VarInt),
734    0x04 :: PickedUp(VarInt),
735    0x05 :: Dropped(VarInt),
736    0x06 :: Killed(VarInt),
737    0x07 :: KilledBy(VarInt),
738    0x08 :: Custom(StatisticKind)
739);
740
741proto_varint_enum!(StatisticKind,
742    0x00 :: LeaveGame,
743    0x01 :: PlayOneMinute,
744    0x02 :: TimeSinceDeath,
745    0x03 :: SneakTime,
746    0x04 :: WealkOneCm,
747    0x05 :: CrouchOneCm,
748    0x06 :: SprintOneCm,
749    0x07 :: SwimOneCm,
750    0x08 :: FallOneCm,
751    0x09 :: ClimbOneCm,
752    0x0A :: FlyOneCm,
753    0x0B :: DiveOneCm,
754    0x0C :: MinecartOneCm,
755    0x0D :: BoatOneCm,
756    0x0E :: PigOneCm,
757    0x0F :: HorseOneCm,
758    0x10 :: AviateOneCm,
759    0x11 :: Jumps,
760    0x12 :: Drops,
761    0x13 :: DamageDealt,
762    0x14 :: DamageTaken,
763    0x15 :: Deaths,
764    0x16 :: MobKills,
765    0x17 :: AnimalsBread,
766    0x18 :: PlayerKills,
767    0x19 :: FishCaught,
768    0x1A :: TalkedToVillager,
769    0x1B :: TradedWithVillager,
770    0x1C :: EatCakeSlice,
771    0x1D :: FillCauldron,
772    0x1E :: UseCauldron,
773    0x1F :: CleanArmor,
774    0x20 :: CleanBanner,
775    0x21 :: InteractWithBrewingStand,
776    0x22 :: InteractWithBeaccon,
777    0x23 :: InspectDropper,
778    0x24 :: InspectHopper,
779    0x25 :: InspectDispenser,
780    0x26 :: PlayNoteBlock,
781    0x27 :: TuneNoteBlock,
782    0x28 :: PotFlower,
783    0x29 :: TriggerTrappedChest,
784    0x2A :: OpenEnderChest,
785    0x2B :: EnchantItem,
786    0x2C :: PlayRecord,
787    0x2D :: InteractWithFurnace,
788    0x2E :: InteractWithCraftingTable,
789    0x2F :: OpenChest,
790    0x30 :: SleepInBed,
791    0x31 :: OpenShulkerBox
792);
793
794proto_struct!(Statistic {
795    kind: StatisticCategory,
796    value: VarInt
797});
798
799proto_byte_enum!(DiggingStatus,
800    0x00 :: Started,
801    0x01 :: Cancelled,
802    0x02 :: Finished
803);
804
805proto_byte_enum!(BlockEntityDataAction,
806    0x01 :: SetMobSpawnerData,
807    0x02 :: SetCommandBlockText,
808    0x03 :: SetBeaconLevelAndPower,
809    0x04 :: SetMobHeadRotationAndSkin,
810    0x05 :: DeclareConduit,
811    0x06 :: SetBannerColorAndPatterns,
812    0x07 :: SetStructureTileEntityData,
813    0x08 :: SetEndGatewayDestination,
814    0x09 :: SetSignText,
815    0x0B :: DeclareBed,
816    0x0C :: SetJigsawBlockData,
817    0x0D :: SetCampfireItems,
818    0x0E :: BeehiveInformation
819);
820
821proto_byte_enum!(Difficulty,
822    0x00 :: Peaceful,
823    0x01 :: Easy,
824    0x02 :: Normal,
825    0x03 :: Hard
826);
827
828proto_byte_enum!(ChatPosition,
829    0x00 :: ChatBox,
830    0x01 :: SystemMessage,
831    0x02 :: Hotbar
832);
833
834#[derive(Copy, Clone, PartialEq, Debug)]
835pub struct BlockChangeHorizontalPosition {
836    pub rel_x: u8,
837    pub rel_z: u8,
838}
839
840impl Serialize for BlockChangeHorizontalPosition {
841    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
842        to.serialize_byte((self.rel_x & 0xF) << 4 | (self.rel_z & 0xF))
843    }
844}
845
846impl Deserialize for BlockChangeHorizontalPosition {
847    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
848        Ok(
849            u8::mc_deserialize(data)?.map(move |b| BlockChangeHorizontalPosition {
850                rel_x: (b >> 4) & 0xF,
851                rel_z: b & 0xF,
852            }),
853        )
854    }
855}
856
857#[cfg(all(test, feature = "std"))]
858impl TestRandom for BlockChangeHorizontalPosition {
859    fn test_gen_random() -> Self {
860        BlockChangeHorizontalPosition {
861            rel_x: rand::random::<u8>() % 16,
862            rel_z: rand::random::<u8>() % 16,
863        }
864    }
865}
866
867proto_struct!(MultiBlockChangeRecord {
868    horizontal_position: BlockChangeHorizontalPosition,
869    y_coordinate: u8,
870    block_id: VarInt
871});
872
873proto_varint_enum!(BossBarAction,
874    0x00 :: Add(BossBarAddSpec),
875    0x01 :: Remove,
876    0x02 :: UpdateHealth(BossBarUpdateHealthSpec),
877    0x03 :: UpdateTitle(BossBarUpdateTitleSpec),
878    0x04 :: UpdateStyle(BossBarUpdateStyleSpec),
879    0x05 :: UpdateFlags(BossBarUpdateFlagsSpec)
880);
881
882proto_varint_enum!(BossBarColor,
883    0x00 :: Pink,
884    0x01 :: Blue,
885    0x02 :: Red,
886    0x03 :: Green,
887    0x04 :: Yellow,
888    0x05 :: Purple,
889    0x06 :: White
890);
891
892proto_varint_enum!(BossBarDivision,
893    0x00 :: NoDivision,
894    0x01 :: SixNotches,
895    0x02 :: TenNotches,
896    0x03 :: TwelveNotches,
897    0x04 :: TwentyNotches
898);
899
900proto_byte_flag!(BossBarFlags,
901    0x01 :: is_darken_sky set_darken_sky,
902    0x02 :: is_dragon_bar set_dragon_bar,
903    0x04 :: is_create_fog set_create_fog
904);
905
906proto_struct!(BossBarAddSpec {
907    title: Chat,
908    health: f32,
909    color: BossBarColor,
910    division: BossBarDivision,
911    flags: BossBarFlags
912});
913
914proto_struct!(BossBarUpdateHealthSpec { health: f32 });
915
916proto_struct!(BossBarUpdateTitleSpec { title: String });
917
918proto_struct!(BossBarUpdateStyleSpec {
919    color: BossBarColor,
920    dividers: BossBarDivision
921});
922
923proto_struct!(BossBarUpdateFlagsSpec {
924    flags: BossBarFlags
925});
926
927proto_struct!(TabCompleteMatch {
928    match_: String,
929    tooltip: Option<Chat>
930});
931
932#[derive(Clone, Debug, PartialEq)]
933pub struct CommandNodeSpec {
934    pub children_indices: CountedArray<VarInt, VarInt>,
935    pub redirect_node: Option<VarInt>,
936    pub is_executable: bool,
937    pub node: CommandNode,
938}
939
940#[derive(Clone, Debug, PartialEq)]
941pub enum CommandNode {
942    Root,
943    Argument(CommandArgumentNodeSpec),
944    Literal(CommandLiteralNodeSpec)
945}
946
947impl Serialize for CommandNodeSpec {
948    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
949        let mut flags: u8 = 0;
950
951        use CommandNode::*;
952
953        flags |= match &self.node {
954            Root => 0x00,
955            Literal(_) => 0x01,
956            Argument(_) => 0x02,
957        };
958
959        if self.is_executable {
960            flags |= 0x04;
961        }
962
963        if self.redirect_node.is_some() {
964            flags |= 0x08;
965        }
966
967        if let Argument(body) = &self.node {
968            if body.suggestions_types.is_some() {
969                flags |= 0x10
970            }
971        }
972
973        to.serialize_byte(flags)?;
974        to.serialize_other(&self.children_indices)?;
975        if let Some(redirect_node) = &self.redirect_node {
976            to.serialize_other(redirect_node)?;
977        }
978
979        match &self.node {
980            Root => Ok(()),
981            Argument(body) => body.serialize(to),
982            Literal(body) => to.serialize_other(body),
983        }
984    }
985}
986
987impl Deserialize for CommandNodeSpec {
988    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
989        let Deserialized { value: flags, data } = u8::mc_deserialize(data)?;
990        let Deserialized { value: children_indices, data } = <CountedArray<VarInt, VarInt>>::mc_deserialize(data)?;
991        let (redirect_node, data) = if flags & 0x08 != 0 {
992            let Deserialized { value: redirect_node, data } = VarInt::mc_deserialize(data)?;
993            (Some(redirect_node), data)
994        } else {
995            (None, data)
996        };
997        let is_executable = flags & 0x04 != 0;
998
999        use CommandNode::*;
1000        let Deserialized{ value: node, data } = match flags & 0x03 {
1001            0x00 => Deserialized::ok(Root, data),
1002            0x01 => Ok(CommandLiteralNodeSpec::mc_deserialize(data)?.map(move |body| Literal(body))),
1003            0x02 => Ok(CommandArgumentNodeSpec::deserialize(flags & 0x10 != 0, data)?.map(move |body| Argument(body))),
1004            other => panic!("impossible condition (bitmask) {}", other)
1005        }?;
1006
1007        Deserialized::ok(Self {
1008            children_indices,
1009            redirect_node,
1010            is_executable,
1011            node
1012        }, data)
1013    }
1014}
1015
1016#[cfg(all(test, feature = "std"))]
1017impl TestRandom for CommandNodeSpec {
1018    fn test_gen_random() -> Self {
1019        let children_indices = <CountedArray<VarInt, VarInt>>::test_gen_random();
1020        let redirect_node = <Option<VarInt>>::test_gen_random();
1021        let is_executable = rand::random::<bool>();
1022        let idx = rand::random::<usize>() % 3;
1023        let node = match idx {
1024            0 => CommandNode::Root,
1025            1 => CommandNode::Argument(CommandArgumentNodeSpec::test_gen_random()),
1026            2 => CommandNode::Literal(CommandLiteralNodeSpec::test_gen_random()),
1027            other => panic!("impossible state {}", other)
1028        };
1029
1030        Self {
1031            children_indices,
1032            redirect_node,
1033            is_executable,
1034            node,
1035        }
1036    }
1037}
1038
1039#[derive(Clone, Debug, PartialEq)]
1040pub struct CommandArgumentNodeSpec {
1041    pub name: String,
1042    pub parser: CommandParserSpec,
1043    pub suggestions_types: Option<SuggestionsTypeSpec>,
1044}
1045
1046impl CommandArgumentNodeSpec {
1047    fn serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1048        to.serialize_other(&self.name)?;
1049        to.serialize_other(&self.parser)?;
1050        if let Some(suggestions_types) = &self.suggestions_types {
1051            to.serialize_other(suggestions_types)?;
1052        }
1053
1054        Ok(())
1055    }
1056
1057    fn deserialize(has_suggestion_types: bool, data: &[u8]) -> DeserializeResult<Self> {
1058        let Deserialized { value: name, data } = String::mc_deserialize(data)?;
1059        let Deserialized { value: parser, data } = CommandParserSpec::mc_deserialize(data)?;
1060        let (suggestions_types, data) = if has_suggestion_types {
1061            let Deserialized { value: suggestions_types, data } = SuggestionsTypeSpec::mc_deserialize(data)?;
1062            (Some(suggestions_types), data)
1063        } else {
1064            (None, data)
1065        };
1066
1067        Deserialized::ok(Self {
1068            name,
1069            parser,
1070            suggestions_types,
1071        }, data)
1072    }
1073}
1074
1075#[cfg(all(test, feature = "std"))]
1076impl TestRandom for CommandArgumentNodeSpec {
1077    fn test_gen_random() -> Self {
1078        let name = String::test_gen_random();
1079        let suggestions_types = <Option<SuggestionsTypeSpec>>::test_gen_random();
1080        let parser = CommandParserSpec::test_gen_random();
1081
1082        Self {
1083            name,
1084            parser,
1085            suggestions_types,
1086        }
1087    }
1088}
1089
1090proto_str_enum!(SuggestionsTypeSpec,
1091    "minecraft:ask_server" :: AskServer,
1092    "minecraft:all_recipes" :: AllRecipes,
1093    "minecraft:available_sounds" :: AvailableSounds,
1094    "minecraft:summonable_entities" :: SummonableEntities
1095);
1096
1097proto_struct!(CommandLiteralNodeSpec {
1098    name: String
1099});
1100
1101proto_str_enum!(CommandParserSpec,
1102    "brigadier:bool" :: Bool,
1103    "brigadier:double" :: Double(DoubleParserProps),
1104    "brigadier:float" :: Float(FloatParserProps),
1105    "brigadier:integer" :: Integer(IntegerParserProps),
1106    "brigadier:string" :: StringParser(StringParserMode),
1107    "minecraft:entity" :: Entity(EntityParserFlags),
1108    "minecraft:game_profile" :: GameProfile,
1109    "minecraft:block_pos" :: BlockPosition,
1110    "minecraft:column_pos" :: ColumnPosition,
1111    "minecraft:vec3" :: Vec3,
1112    "minecraft:vec2" :: Vec2,
1113    "minecraft:block_state" :: BlockState,
1114    "minecraft:block_predicate" :: BlockPredicate,
1115    "minecraft:item_stack" :: ItemStack,
1116    "minecraft:item_predicate" :: ItemPredicate,
1117    "minecraft:color" :: Color,
1118    "minecraft:component" :: Component,
1119    "minecraft:message" :: Message,
1120    "minecraft:nbt" :: Nbt,
1121    "minecraft:nbt_path" :: NbtPath,
1122    "minecraft:objective" :: Objective,
1123    "minecraft:objective_criteria" :: ObjectiveCriteria,
1124    "minecraft:operation" :: Operation,
1125    "minecraft:particle" :: Particle,
1126    "minecraft:rotation" :: Rotation,
1127    "minecraft:scoreboard_slot" :: ScoreboardSlot,
1128    "minecraft:score_holder" :: ScoreHolder(ScoreHolderFlags),
1129    "minecraft:swizzle" :: Swizzle,
1130    "minecraft:team" :: Team,
1131    "minecraft:item_slot" :: ItemSlot,
1132    "minecraft:resource_location" :: ResourceLocation,
1133    "minecraft:mob_effect" :: MobEffect,
1134    "minecraft:function" :: Function,
1135    "minecraft:entity_anchor" :: EntityAnchor,
1136    "minecraft:range" :: Range(RangeParserProps),
1137    "minecraft:int_range" :: IntRange,
1138    "minecraft:float_range" :: FloatRange,
1139    "minecraft:item_enchantment" :: ItemEnchantment,
1140    "minecraft:entity_summon" :: EntitySummon,
1141    "minecraft:dimension" :: Dimension,
1142    "minecraft:uuid" :: UUID,
1143    "minecraft:nbt_tag" :: NbtTag,
1144    "minecraft:nbt_compound_tag" :: NbtCompoundTag,
1145    "minecraft:time" :: Time
1146);
1147
1148pub struct NumParserProps<T> {
1149    pub min: Option<T>,
1150    pub max: Option<T>,
1151}
1152
1153pub type DoubleParserProps = NumParserProps<f64>;
1154
1155pub type FloatParserProps = NumParserProps<f32>;
1156
1157pub type IntegerParserProps = NumParserProps<i32>;
1158
1159impl<T> Copy for NumParserProps<T> where T: Copy {}
1160
1161impl<T> Clone for NumParserProps<T> where T: Clone {
1162    fn clone(&self) -> Self {
1163        Self {
1164            min: self.min.clone(),
1165            max: self.max.clone(),
1166        }
1167    }
1168}
1169
1170impl<T> Debug for NumParserProps<T> where T: Debug {
1171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1172        write!(f, "NumParserProps(min={:?}, max={:?})", self.min, self.max)
1173    }
1174}
1175
1176impl<T> PartialEq for NumParserProps<T> where T: PartialEq {
1177    fn eq(&self, other: &Self) -> bool {
1178        other.max.eq(&self.max) && other.min.eq(&self.min)
1179    }
1180}
1181
1182impl<T> Serialize for NumParserProps<T> where T: Serialize {
1183    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1184        let mut flags: u8 = 0;
1185        if self.min.is_some() {
1186            flags |= 0x01;
1187        }
1188
1189        if self.max.is_some() {
1190            flags |= 0x02;
1191        }
1192
1193        to.serialize_other(&flags)?;
1194        if let Some(min) = &self.min {
1195            to.serialize_other(min)?;
1196        }
1197
1198        if let Some(max) = &self.max {
1199            to.serialize_other(max)?;
1200        }
1201
1202        Ok(())
1203    }
1204}
1205
1206impl<T> Deserialize for NumParserProps<T> where T: Deserialize {
1207    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
1208        let Deserialized { value: flags, data } = u8::mc_deserialize(data)?;
1209        let (min, data) = if flags & 0x01 != 0 {
1210            let Deserialized { value: min, data } = T::mc_deserialize(data)?;
1211            (Some(min), data)
1212        } else {
1213            (None, data)
1214        };
1215
1216        let (max, data) = if flags & 0x02 != 0 {
1217            let Deserialized { value: max, data } = T::mc_deserialize(data)?;
1218            (Some(max), data)
1219        } else {
1220            (None, data)
1221        };
1222
1223        let out = Self {
1224            min,
1225            max,
1226        };
1227        Deserialized::ok(out, data)
1228    }
1229}
1230
1231#[cfg(all(test, feature = "std"))]
1232impl<T> TestRandom for NumParserProps<T> where
1233    T: TestRandom + std::cmp::PartialOrd,
1234    rand::distributions::Standard: rand::distributions::Distribution<T>,
1235{
1236    fn test_gen_random() -> Self {
1237        let has_min = rand::random::<bool>();
1238        let has_max = rand::random::<bool>();
1239        let (min, max) = if has_min && has_max {
1240            let a = rand::random::<T>();
1241            let b = rand::random::<T>();
1242            if a < b {
1243                (Some(a), Some(b))
1244            } else {
1245                (Some(b), Some(a))
1246            }
1247        } else if !has_min && !has_max {
1248            (None, None)
1249        } else {
1250            let v = rand::random::<T>();
1251            if has_min {
1252                (Some(v), None)
1253            } else {
1254                (None, Some(v))
1255            }
1256        };
1257
1258        Self {
1259            min,
1260            max,
1261        }
1262    }
1263}
1264
1265proto_varint_enum!(StringParserMode,
1266    0x00 :: SingleWord,
1267    0x01 :: QuotablePharse,
1268    0x02 :: GreedyPhrase
1269);
1270
1271proto_byte_flag!(EntityParserFlags,
1272    0x01 :: is_single_target set_single_target,
1273    0x02 :: is_players_only set_players_only
1274);
1275
1276proto_byte_flag!(ScoreHolderFlags,
1277    0x01 :: is_multiple set_multiple
1278);
1279
1280proto_struct!(RangeParserProps {
1281    decimal: bool
1282});
1283
1284proto_byte_enum!(TeamAction,
1285    0x00 :: Create(TeamActionCreateSpec),
1286    0x01 :: Remove,
1287    0x02 :: UpdateInfo(TeamActionUpdateInfoSpec),
1288    0x03 :: AddPlayers(TeamActionPlayerList),
1289    0x04 :: RemovePlayers(TeamActionPlayerList)
1290);
1291
1292#[derive(Clone, Debug, PartialEq)]
1293pub enum TeamMember {
1294    Player(String),
1295    Entity(UUID4),
1296}
1297
1298impl Serialize for TeamMember {
1299    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1300        use TeamMember::*;
1301        match self {
1302            Player(username) => username.mc_serialize(to),
1303            Entity(entity_id) => entity_id.to_string().mc_serialize(to),
1304        }
1305    }
1306}
1307
1308impl Deserialize for TeamMember {
1309    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
1310        use TeamMember::*;
1311
1312        Ok(String::mc_deserialize(data)?.map(move |raw| {
1313            if let Some(entity_id) = UUID4::parse(raw.as_str()) {
1314                Entity(entity_id)
1315            } else {
1316                Player(raw)
1317            }
1318        }))
1319    }
1320}
1321
1322#[cfg(all(test, feature = "std"))]
1323impl TestRandom for TeamMember {
1324    fn test_gen_random() -> Self {
1325        use TeamMember::*;
1326
1327        let rand_bool: bool = rand::random();
1328        if rand_bool {
1329            Player(String::test_gen_random())
1330        } else {
1331            Entity(UUID4::random())
1332        }
1333    }
1334}
1335
1336proto_str_enum!(TeamTagNameVisibility,
1337    "always" :: Always,
1338    "hideForOtherTeams" :: HideForOtherTeams,
1339    "hideForOwnTeam" :: HideForOwnTeam,
1340    "never" :: Never
1341);
1342
1343proto_str_enum!(TeamCollisionRule,
1344    "always" :: Always,
1345    "pushForOtherTeams" :: PushForOtherTeams,
1346    "pushOwnTeam" :: PushOwnTeam,
1347    "never" :: Never
1348);
1349
1350proto_struct!(TeamActionPlayerList {
1351    entities: CountedArray<TeamMember, VarInt>
1352});
1353
1354proto_struct!(TeamActionCreateSpec {
1355    display_name: Chat,
1356    friendly_flags: TeamFriendlyFlags,
1357    tag_name_visibility: TeamTagNameVisibility,
1358    collision_rule: TeamCollisionRule,
1359    color: VarInt,
1360    prefix: Chat,
1361    suffix: Chat,
1362    entities: CountedArray<TeamMember, VarInt>
1363});
1364
1365proto_struct!(TeamActionUpdateInfoSpec {
1366    display_name: Chat,
1367    friendly_flags: TeamFriendlyFlags,
1368    tag_name_visibility: TeamTagNameVisibility,
1369    collision_rule: TeamCollisionRule,
1370    color: VarInt,
1371    prefix: Chat,
1372    suffix: Chat
1373});
1374
1375proto_byte_flag!(TeamFriendlyFlags,
1376    0x01 :: allow_friendly_fire set_friendly_fire,
1377    0x02 :: show_invisible_teammates set_show_invisible_teammates
1378);
1379
1380proto_byte_enum!(UpdateScoreAction,
1381    0x00 :: Upsert(VarInt),
1382    0x01 :: Remove
1383);
1384
1385#[derive(Clone, Debug, PartialEq)]
1386pub struct UpdateScoreSpec {
1387    pub objective_name: String,
1388    pub action: UpdateScoreAction,
1389}
1390
1391impl Serialize for UpdateScoreSpec {
1392    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1393        to.serialize_byte(self.action.id())?;
1394        to.serialize_other(&self.objective_name)?;
1395        self.action.serialize_body(to)?;
1396
1397        Ok(())
1398    }
1399}
1400
1401impl Deserialize for UpdateScoreSpec {
1402    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
1403        let Deserialized { value: action_id, data } = u8::mc_deserialize(data)?;
1404        let Deserialized { value: objective_name, data } = String::mc_deserialize(data)?;
1405
1406        Ok(UpdateScoreAction::deserialize_with_id(action_id, data)?.map(move |action| {
1407            Self {
1408                objective_name,
1409                action,
1410            }
1411        }))
1412    }
1413}
1414
1415#[cfg(all(test, feature = "std"))]
1416impl TestRandom for UpdateScoreSpec {
1417    fn test_gen_random() -> Self {
1418        Self {
1419            objective_name: String::test_gen_random(),
1420            action: UpdateScoreAction::test_gen_random(),
1421        }
1422    }
1423}
1424
1425proto_varint_enum!(TitleActionSpec,
1426    0x00 :: SetTitle(Chat),
1427    0x01 :: SetSubtitle(Chat),
1428    0x02 :: SetActionBar(Chat),
1429    0x03 :: SetTimesAndDisplay(TitleTimesSpec),
1430    0x04 :: Hide,
1431    0x05 :: Reset
1432);
1433
1434proto_struct!(TitleTimesSpec {
1435    fade_in: i32,
1436    stay: i32,
1437    fade_out: i32
1438});
1439
1440proto_varint_enum!(SoundCategory,
1441    0x00 :: Master,
1442    0x01 :: Music,
1443    0x02 :: Records,
1444    0x03 :: Weather,
1445    0x04 :: Block,
1446    0x05 :: Hostile,
1447    0x06 :: Neutral,
1448    0x07 :: Player,
1449    0x08 :: Ambient,
1450    0x09 :: Voice
1451);
1452
1453#[derive(Clone, Debug, PartialEq)]
1454pub struct StopSoundSpec {
1455    pub source: Option<SoundCategory>,
1456    pub sound: Option<String>,
1457}
1458
1459impl Serialize for StopSoundSpec {
1460    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1461        let has_sound = self.sound.is_some();
1462        let has_source = self.source.is_some();
1463        let mut flags = 0;
1464        if has_sound {
1465            flags |= 0x02;
1466        }
1467        if has_source {
1468            flags |= 0x01;
1469        }
1470
1471        to.serialize_byte(flags)?;
1472        if let Some(source) = &self.source {
1473            to.serialize_other(source)?;
1474        }
1475
1476        if let Some(sound) = &self.sound {
1477            to.serialize_other(sound)?;
1478        }
1479
1480        Ok(())
1481    }
1482}
1483
1484impl Deserialize for StopSoundSpec {
1485    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
1486        let Deserialized { value: flags, data } = u8::mc_deserialize(data)?;
1487
1488        let is_source_present = flags & 0x01 != 0;
1489        let is_sound_present = flags & 0x02 != 0;
1490
1491        let (source, data) = if is_source_present {
1492            let Deserialized { value: source, data } = SoundCategory::mc_deserialize(data)?;
1493            (Some(source), data)
1494        } else {
1495            (None, data)
1496        };
1497
1498        let (sound, data) = if is_sound_present {
1499            let Deserialized { value: sound, data } = String::mc_deserialize(data)?;
1500            (Some(sound), data)
1501        } else {
1502            (None, data)
1503        };
1504
1505        Deserialized::ok(Self {
1506            source,
1507            sound,
1508        }, data)
1509    }
1510}
1511
1512#[cfg(all(test, feature = "std"))]
1513impl TestRandom for StopSoundSpec {
1514    fn test_gen_random() -> Self {
1515        let source = if rand::random::<bool>() {
1516            Some(SoundCategory::test_gen_random())
1517        } else {
1518            None
1519        };
1520
1521        let sound = if source.is_none() || rand::random::<bool>() {
1522            Some(String::test_gen_random())
1523        } else {
1524            None
1525        };
1526
1527        Self {
1528            source,
1529            sound,
1530        }
1531    }
1532}
1533
1534proto_byte_enum!(GameMode,
1535    0x00 :: Survival,
1536    0x01 :: Creative,
1537    0x02 :: Adventure,
1538    0x03 :: Spectator
1539);
1540
1541proto_byte_enum!(WinGameAction,
1542    0x00 :: Respawn,
1543    0x01 :: RollCreditsAndRespawn
1544);
1545
1546proto_byte_enum!(DemoEvent,
1547    0x00 :: ShowWelcomeScreen,
1548    0x65 :: TellMovementControls,
1549    0x66 :: TellJumpControl,
1550    0x67 :: TellInventoryControl,
1551    0x68 :: EndDemo
1552);
1553
1554proto_byte_enum!(RespawnRequestType,
1555    0x00 :: Screen,
1556    0x01 :: Immediate
1557);
1558
1559proto_int_enum!(Dimension,
1560    -0x01 :: Nether,
1561     0x00 :: Overworld,
1562     0x01 :: End
1563);
1564
1565#[derive(Clone, Debug, PartialEq)]
1566pub enum GameChangeReason {
1567    NoRespawnAvailable,
1568    EndRaining,
1569    BeginRaining,
1570    ChangeGameMode(GameMode),
1571    WinGame(WinGameAction),
1572    Demo(DemoEvent),
1573    ArrowHitPlayer,
1574    RainLevelChange(f32),
1575    ThunderLevelChange(f32),
1576    PufferfishSting,
1577    ElderGuardianMobAppearance,
1578    Respawn(RespawnRequestType),
1579}
1580
1581impl Serialize for GameChangeReason {
1582    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1583        use GameChangeReason::*;
1584        to.serialize_byte(match self {
1585            NoRespawnAvailable => 0x00,
1586            EndRaining => 0x01,
1587            BeginRaining => 0x02,
1588            ChangeGameMode(_) => 0x03,
1589            WinGame(_) => 0x04,
1590            Demo(_) => 0x05,
1591            ArrowHitPlayer => 0x06,
1592            RainLevelChange(_) => 0x07,
1593            ThunderLevelChange(_) => 0x08,
1594            PufferfishSting => 0x09,
1595            ElderGuardianMobAppearance => 0x0A,
1596            Respawn(_) => 0x0B,
1597        })?;
1598
1599        let value = match self {
1600            ChangeGameMode(body) => body.id() as f32,
1601            WinGame(body) => body.id() as f32,
1602            Demo(body) => body.id() as f32,
1603            RainLevelChange(body) => *body,
1604            ThunderLevelChange(body) => *body,
1605            Respawn(body) => body.id() as f32,
1606            _ => 0 as f32,
1607        };
1608        to.serialize_other(&value)
1609    }
1610}
1611
1612impl Deserialize for GameChangeReason {
1613    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
1614        let Deserialized {
1615            value: reason_id,
1616            data,
1617        } = u8::mc_deserialize(data)?;
1618        let Deserialized { value, data } = f32::mc_deserialize(data)?;
1619        use GameChangeReason::*;
1620        match reason_id {
1621            0x00 => Deserialized::ok(NoRespawnAvailable, data),
1622            0x01 => Deserialized::ok(EndRaining, data),
1623            0x02 => Deserialized::ok(BeginRaining, data),
1624            0x03 => Ok(GameMode::deserialize_with_id(value as u8, data)?.map(move |mode| ChangeGameMode(mode))),
1625            0x04 => Ok(WinGameAction::deserialize_with_id(value as u8, data)?.map(move |mode| WinGame(mode))),
1626            0x05 => Ok(DemoEvent::deserialize_with_id(value as u8, data)?.map(move |mode| Demo(mode))),
1627            0x06 => Deserialized::ok(ArrowHitPlayer, data),
1628            0x07 => Deserialized::ok(RainLevelChange(value), data),
1629            0x08 => Deserialized::ok(ThunderLevelChange(value), data),
1630            0x09 => Deserialized::ok(PufferfishSting, data),
1631            0x0A => Deserialized::ok(ElderGuardianMobAppearance, data),
1632            0x0B => Ok(RespawnRequestType::deserialize_with_id(value as u8, data)?.map(move |mode| Respawn(mode))),
1633            other => Err(DeserializeErr::CannotUnderstandValue(alloc::format!(
1634                "invalid game change reason id {}",
1635                other
1636            ))),
1637        }
1638    }
1639}
1640
1641#[cfg(all(test, feature = "std"))]
1642impl TestRandom for GameChangeReason {
1643    fn test_gen_random() -> Self {
1644        // todo
1645        GameChangeReason::PufferfishSting
1646    }
1647}
1648
1649proto_varint_enum!(MapIconType,
1650    0x00 :: WhiteArrow,
1651    0x01 :: GreenArrow,
1652    0x02 :: RedArrow,
1653    0x03 :: BlueArrow,
1654    0x04 :: WhiteCross,
1655    0x05 :: RedPointer,
1656    0x06 :: WhiteCircle,
1657    0x07 :: SmallWhiteCircle,
1658    0x08 :: Mansion,
1659    0x09 :: Temple,
1660    0x0A :: WhiteBanner,
1661    0x0B :: OrangeBanner,
1662    0x0C :: MagentaBanner,
1663    0x0D :: YellowBanner,
1664    0x0E :: LimeBanner,
1665    0x0F :: PinkBanner,
1666    0x10 :: GrayBanner,
1667    0x11 :: LightGrayBanner,
1668    0x12 :: CyanBanner,
1669    0x13 :: PurpleBanner,
1670    0x14 :: BlueBanner,
1671    0x15 :: BrownBanner,
1672    0x16 :: GreenBanner,
1673    0x17 :: RedBanner,
1674    0x18 :: BlackBanner,
1675    0x19 :: TreasureMarker
1676);
1677
1678proto_struct!(MapIconSpec {
1679    kind: MapIconType,
1680    position: TopDownPosition<i8>,
1681    direction: i8,
1682    display_name: Option<Chat>
1683});
1684
1685#[derive(Clone, PartialEq, Debug)]
1686pub enum MapColumns {
1687    NoUpdates,
1688    Updated(MapColumnsSpec),
1689}
1690
1691proto_struct!(MapColumnsSpec {
1692    columns: u8,
1693    rows: u8,
1694    position: TopDownPosition<u8>,
1695    data: CountedArray<u8, VarInt>
1696});
1697
1698impl Serialize for MapColumns {
1699    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1700        use MapColumns::*;
1701        match self {
1702            NoUpdates => to.serialize_other(&0u8),
1703            Updated(body) => to.serialize_other(body),
1704        }
1705    }
1706}
1707
1708impl Deserialize for MapColumns {
1709    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
1710        let Deserialized { value: columns, data: rest } = u8::mc_deserialize(data)?;
1711        use MapColumns::*;
1712        match columns {
1713            0x00 => Deserialized::ok(NoUpdates, rest),
1714            _ => Ok(MapColumnsSpec::mc_deserialize(data)?.map(move |v| Updated(v))),
1715        }
1716    }
1717}
1718
1719impl Into<Option<MapColumnsSpec>> for MapColumns {
1720    fn into(self) -> Option<MapColumnsSpec> {
1721        use MapColumns::*;
1722        match self {
1723            NoUpdates => None,
1724            Updated(body) => Some(body),
1725        }
1726    }
1727}
1728
1729impl From<Option<MapColumnsSpec>> for MapColumns {
1730    fn from(other: Option<MapColumnsSpec>) -> Self {
1731        use MapColumns::*;
1732        match other {
1733            Some(body) => {
1734                if body.columns == 0 {
1735                    NoUpdates
1736                } else {
1737                    Updated(body)
1738                }
1739            },
1740            None => NoUpdates,
1741        }
1742    }
1743}
1744
1745#[cfg(all(test, feature = "std"))]
1746impl TestRandom for MapColumns {
1747    fn test_gen_random() -> Self {
1748        <Option<MapColumnsSpec>>::test_gen_random().into()
1749    }
1750}
1751
1752proto_struct!(TradeSpec {
1753    input_item_1: Slot,
1754    output_item: Slot,
1755    input_item_2: Slot,
1756    trade_disabled: bool,
1757    trade_uses: i32,
1758    max_trade_uses: i32,
1759    xp: i32,
1760    special_price: i32,
1761    price_multiplier: f32,
1762    demand: i32
1763});
1764
1765proto_varint_enum!(Hand,
1766    0x00 :: MainHand,
1767    0x01 :: OffHand
1768);
1769
1770proto_varint_enum!(WindowType,
1771    0x00 :: GenericOneRow,
1772    0x01 :: GenericTwoRow,
1773    0x02 :: GenericThreeRow,
1774    0x03 :: GenericFourRow,
1775    0x04 :: GenericFiveRow,
1776    0x05 :: GenericSixRow,
1777    0x06 :: GenericSquare,
1778    0x07 :: Anvil,
1779    0x08 :: Beacon,
1780    0x09 :: BlastFurnace,
1781    0x0A :: BrewingStand,
1782    0x0B :: CraftingTable,
1783    0x0C :: EnchantmentTable,
1784    0x0D :: Furnace,
1785    0x0E :: Grindstone,
1786    0x0F :: Hopper,
1787    0x10 :: Lectern,
1788    0x11 :: Loom,
1789    0x12 :: Merchant,
1790    0x13 :: ShulkerBox,
1791    0x14 :: Smoker,
1792    0x15 :: Cartography,
1793    0x16 :: StoneCutter
1794);
1795
1796proto_byte_flag!(PlayerAbilityFlags,
1797    0x01 :: is_invulnerable set_invulnerable,
1798    0x02 :: is_flying set_flying,
1799    0x04 :: is_flight_allowed set_flight_allowed,
1800    0x08 :: is_instant_break set_instant_break
1801);
1802
1803proto_varint_enum!(CombatEvent,
1804    0x00 :: Enter,
1805    0x01 :: End(CombatEndSpec),
1806    0x02 :: EntityDead(CombatEntityDeadSpec)
1807);
1808
1809proto_struct!(CombatEndSpec {
1810    duration_ticks: VarInt,
1811    entity_id: i32
1812});
1813
1814proto_struct!(CombatEntityDeadSpec {
1815    player_id: VarInt,
1816    entity_id: i32,
1817    message: Chat
1818});
1819
1820proto_struct!(PlayerInfoAction<A> {
1821    uuid: UUID4,
1822    action: A
1823});
1824
1825proto_varint_enum!(PlayerInfoActionList,
1826    0x00 :: Add(CountedArray<PlayerInfoAction<PlayerAddActionSpec>, VarInt>),
1827    0x01 :: UpdateGameMode(CountedArray<PlayerInfoAction<GameMode>, VarInt>),
1828    0x02 :: UpdateLatency(CountedArray<PlayerInfoAction<VarInt>, VarInt>),
1829    0x03 :: UpdateDisplayName(CountedArray<PlayerInfoAction<Option<Chat>>, VarInt>),
1830    0x04 :: Remove(CountedArray<UUID4, VarInt>)
1831);
1832
1833proto_struct!(PlayerAddActionSpec {
1834    name: String,
1835    properties: CountedArray<PlayerAddProperty, VarInt>,
1836    game_mode: GameMode,
1837    ping_ms: VarInt,
1838    display_name: Option<Chat>
1839});
1840
1841proto_struct!(PlayerAddProperty {
1842    name: String,
1843    value: String,
1844    signature: Option<String>
1845});
1846
1847proto_varint_enum!(FacePlayerKind,
1848    0x00 :: Feet,
1849    0x01 :: Eyes
1850);
1851
1852proto_struct!(FacePlayerEntityTarget {
1853    entity_id: VarInt,
1854    kind: FacePlayerKind
1855});
1856
1857proto_byte_flag!(PositionAndLookFlags,
1858    0x01 :: is_x_rel set_x_rel,
1859    0x02 :: is_y_rel set_y_rel,
1860    0x04 :: is_z_rel set_z_rel,
1861    0x08 :: is_y_rotation_rel set_y_rotation_rel,
1862    0x10 :: is_x_rotation_rel set_x_rotation_rel
1863);
1864
1865proto_byte_enum!(EntityEffectKind,
1866    0x01 :: Speed,
1867    0x02 :: Slowness,
1868    0x03 :: Haste,
1869    0x04 :: MiningFatigue,
1870    0x05 :: Strength,
1871    0x06 :: InstantHealth,
1872    0x07 :: InstantDamage,
1873    0x08 :: JumpBoost,
1874    0x09 :: Nausea,
1875    0x0A :: Regeneration,
1876    0x0B :: Resistance,
1877    0x0C :: FireResistance,
1878    0x0D :: WaterBreathing,
1879    0x0E :: Invisibility,
1880    0x0F :: Blindness,
1881    0x10 :: NightVision,
1882    0x11 :: Hunger,
1883    0x12 :: Weakness,
1884    0x13 :: Poison,
1885    0x14 :: Wither,
1886    0x15 :: HealthBoost,
1887    0x16 :: Absorption,
1888    0x17 :: Saturation,
1889    0x18 :: Glowing,
1890    0x19 :: Levetation,
1891    0x1A :: Luck,
1892    0x1B :: Unluck,
1893    0x1C :: SlowFalling,
1894    0x1D :: ConduitPower,
1895    0x1E :: DolphinsGrace,
1896    0x1F :: BadOmen,
1897    0x20 :: HeroOfTheVillage
1898);
1899
1900proto_varint_enum!(WorldBorderAction,
1901    0x00 :: SetSize(WorldBorderSetSizeSpec),
1902    0x01 :: LerpSize(WorldBorderLerpSizeSpec),
1903    0x02 :: SetCenter(TopDownPosition<f64>),
1904    0x03 :: Initialize(WorldBorderInitiaializeSpec),
1905    0x04 :: SetWarningTime(WorldBorderWarningTimeSpec),
1906    0x05 :: SetWarningBlocks(WorldBorderWarningBlocksSpec)
1907);
1908
1909proto_struct!(WorldBorderSetSizeSpec {
1910    diameter: f64
1911});
1912
1913proto_struct!(WorldBorderLerpSizeSpec {
1914    old_diameter: f64,
1915    new_diameter: f64,
1916    speed: VarLong
1917});
1918
1919proto_struct!(WorldBorderInitiaializeSpec {
1920    position: TopDownPosition<f64>,
1921    old_diameter: f64,
1922    new_diameter: f64,
1923    speed: VarLong,
1924    portal_teleport_boundary: VarLong,
1925    warning_time: VarInt,
1926    warning_blocks: VarInt
1927});
1928
1929proto_struct!(WorldBorderWarningTimeSpec {
1930    warning_time: VarInt
1931});
1932
1933proto_struct!(WorldBorderWarningBlocksSpec {
1934    warning_blocks: VarInt
1935});
1936
1937proto_byte_enum!(ScoreboardPosition,
1938    0x00 :: List,
1939    0x01 :: Sidebar,
1940    0x02 :: BelowName,
1941    0x03 :: TeamSpecific(i8)
1942);
1943
1944proto_varint_enum!(EquipmentSlot,
1945    0x00 :: MainHand,
1946    0x01 :: OffHand,
1947    0x02 :: ArmorBoots,
1948    0x03 :: ArmorLeggings,
1949    0x04 :: ArmorChestplate,
1950    0x05 :: ArmorHelmet
1951);
1952
1953proto_byte_enum!(ScoreboardObjectiveAction,
1954    0x00 :: Create(ScoreboardObjectiveSpec),
1955    0x01 :: Remove,
1956    0x02 :: UpdateText(ScoreboardObjectiveSpec)
1957);
1958
1959proto_varint_enum!(ScoreboardObjectiveKind,
1960    0x00 :: Integer,
1961    0x01 :: Hearts
1962);
1963
1964proto_struct!(ScoreboardObjectiveSpec {
1965    text: Chat,
1966    kind: ScoreboardObjectiveKind
1967});
1968
1969proto_struct!(AdvancementMappingEntrySpec {
1970    key: String,
1971    value: AdvancementSpec
1972});
1973
1974proto_struct!(AdvancementSpec {
1975    parent: Option<String>,
1976    display: Option<AdvancementDisplaySpec>,
1977    criteria: CountedArray<String, VarInt>,
1978    requirements: CountedArray<CountedArray<String, VarInt>, VarInt>
1979});
1980
1981proto_struct!(AdvancementDisplaySpec {
1982    title: Chat,
1983    description: Chat,
1984    icon: Slot,
1985    frame_type: AdvancementFrameType,
1986    flags: AdvancementDisplayFlags,
1987    position: Vec2<f32>
1988});
1989
1990#[derive(Clone, Debug, PartialEq)]
1991pub struct AdvancementDisplayFlags {
1992    pub background_texture: Option<String>,
1993    pub show_toast: bool,
1994    pub hidden: bool,
1995}
1996
1997impl Serialize for AdvancementDisplayFlags {
1998    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
1999        let mut raw_flags: i32 = 0;
2000        if self.background_texture.is_some() {
2001            raw_flags |= 0x01;
2002        }
2003        if self.show_toast {
2004            raw_flags |= 0x02;
2005        }
2006        if self.hidden {
2007            raw_flags |= 0x04;
2008        }
2009
2010        to.serialize_other(&raw_flags)?;
2011        if let Some(texture) = &self.background_texture {
2012            to.serialize_other(texture)?;
2013        }
2014
2015        Ok(())
2016    }
2017}
2018
2019impl Deserialize for AdvancementDisplayFlags {
2020    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
2021        let Deserialized { value: raw_flags, data } = i32::mc_deserialize(data)?;
2022        let has_background_texture = raw_flags & 0x01 != 0;
2023        let show_toast = raw_flags & 0x02 != 0;
2024        let hidden = raw_flags & 0x04 != 0;
2025
2026        Ok(if has_background_texture {
2027            String::mc_deserialize(data)?.map(move |id| Some(id))
2028        } else {
2029            Deserialized { value: None, data }
2030        }.map(move |background_texture| {
2031            Self {
2032                background_texture,
2033                show_toast,
2034                hidden,
2035            }
2036        }))
2037    }
2038}
2039
2040#[cfg(all(test, feature = "std"))]
2041impl TestRandom for AdvancementDisplayFlags {
2042    fn test_gen_random() -> Self {
2043        let background_texture = if rand::random::<bool>() {
2044            Some(String::test_gen_random())
2045        } else {
2046            None
2047        };
2048        let show_toast = rand::random::<bool>();
2049        let hidden = rand::random::<bool>();
2050
2051        Self {
2052            background_texture,
2053            show_toast,
2054            hidden,
2055        }
2056    }
2057}
2058
2059proto_varint_enum!(AdvancementFrameType,
2060    0x00 :: Task,
2061    0x01 :: Challenge,
2062    0x02 :: Goal
2063);
2064
2065proto_struct!(AdvancementProgressEntrySpec {
2066    key: String,
2067    value: AdvancementProgressSpec
2068});
2069
2070proto_struct!(AdvancementProgressSpec {
2071    criteria: CountedArray<AdvancementCriteriaSpec, VarInt>
2072});
2073
2074proto_struct!(AdvancementCriteriaSpec {
2075    identifier: String,
2076    progress: AdvancementCriterionProgressSpec
2077});
2078
2079proto_struct!(AdvancementCriterionProgressSpec {
2080    achieved_at: Option<i64>
2081});
2082
2083proto_struct!(EntityPropertySpec {
2084    key: String,
2085    value: f64,
2086    modifiers: CountedArray<EntityPropertyModifierSpec, VarInt>
2087});
2088
2089proto_struct!(EntityPropertyModifierSpec {
2090    uuid: UUID4,
2091    amount: f64,
2092    operation: EntityPropertyModifierOperation
2093});
2094
2095proto_byte_enum!(EntityPropertyModifierOperation,
2096    0x00 :: AddSubtractAmount,
2097    0x01 :: AddSubtractAmountPercentOfCurrent,
2098    0x02 :: MultiplyByAmountPercent
2099);
2100
2101proto_byte_flag!(EntityEffectFlags,
2102    0x01 :: is_ambient set_ambient,
2103    0x02 :: is_show_particles set_show_particles,
2104    0x04 :: is_show_icon set_show_icon
2105);
2106
2107proto_struct!(TagSpec {
2108    name: String,
2109    entries: CountedArray<VarInt, VarInt>
2110});
2111
2112proto_varint_enum!(ClientStatusAction,
2113    0x00 :: PerformRespawn,
2114    0x01 :: RequestStats
2115);
2116
2117proto_varint_enum!(ClientChatMode,
2118    0x00 :: Enabled,
2119    0x01 :: CommandsOnly,
2120    0x02 :: Hidden
2121);
2122
2123proto_varint_enum!(ClientMainHand,
2124    0x00 :: Left,
2125    0x01 :: Right
2126);
2127
2128proto_byte_flag!(ClientDisplayedSkinParts,
2129    0x01 :: is_cape_enabled set_cape_enabled,
2130    0x02 :: is_jacket_enabled set_jacket_enabled,
2131    0x04 :: is_left_sleeve_enabled set_left_sleeve_enabled,
2132    0x08 :: is_right_sleeve_enabled set_right_sleeve_enabled,
2133    0x10 :: is_left_pants_leg_enabled set_left_pants_leg_enabled,
2134    0x20 :: is_right_pant_legs_enabled set_right_pant_legs_enabled,
2135    0x40 :: is_hat_enabled set_hat_enabled
2136);
2137
2138proto_varint_enum!(InventoryOperationMode,
2139    0x00 :: MouseClick,
2140    0x01 :: ShiftClick,
2141    0x02 :: NumberClick,
2142    0x03 :: MiddleClick,
2143    0x04 :: DropClick,
2144    0x05 :: Drag,
2145    0x06 :: DoubleClick
2146);
2147
2148proto_struct!(InteractAtSpec {
2149    target_position: Vec3<f32>,
2150    hand: Hand
2151});
2152
2153proto_varint_enum!(InteractKind,
2154    0x00 :: Interact(Hand),
2155    0x01 :: Attack,
2156    0x02 :: InteractAt(InteractAtSpec)
2157);
2158
2159proto_byte_flag!(ClientPlayerAbilities,
2160    0x01 :: is_creative set_creative,
2161    0x02 :: is_flying set_flying,
2162    0x04 :: is_fly_enabled set_fly_enabled,
2163    0x08 :: is_damaged_disabled set_damaged_disabled
2164);
2165
2166proto_varint_enum!(PlayerDiggingStatus,
2167    0x00 :: Started,
2168    0x01 :: Cancelled,
2169    0x02 :: Finished,
2170    0x03 :: DropStack,
2171    0x04 :: DropItem,
2172    0x05 :: ShootArrowOrFishEating,
2173    0x06 :: SwapItemInHand
2174);
2175
2176proto_byte_enum!(DiggingFace,
2177    0x00 :: Bottom,
2178    0x01 :: Top,
2179    0x02 :: North,
2180    0x03 :: South,
2181    0x04 :: West,
2182    0x05 :: East
2183);
2184
2185proto_varint_enum!(EntityActionKind,
2186    0x00 :: StartSneaking,
2187    0x01 :: StopSneaking,
2188    0x02 :: LeaveBed,
2189    0x03 :: StartSprinting,
2190    0x04 :: StopSprinting,
2191    0x05 :: StartJumpWithHorse,
2192    0x06 :: StopJumpWithHorse,
2193    0x07 :: OpenHorseInventory,
2194    0x08 :: StartFlyingWithElytra
2195);
2196
2197proto_byte_flag!(SteerVehicleFlags,
2198    0x01 :: is_jump set_jump,
2199    0x02 :: is_unmount set_unmount
2200);
2201
2202proto_varint_enum!(RecipeBookStatus,
2203    0x00 :: Displayed(String),
2204    0x01 :: States(RecipeBookStates)
2205);
2206
2207proto_struct!(RecipeBookStates {
2208    crafting_book_open: bool,
2209    craftinb_filter_active: bool,
2210    smelting_book_open: bool,
2211    smelting_filter_active: bool,
2212    blasting_book_open: bool,
2213    blasting_filter_active: bool,
2214    smoking_book_open: bool,
2215    smoking_filter_active: bool
2216});
2217
2218proto_varint_enum!(ResourcePackStatus,
2219    0x00 :: Loaded,
2220    0x01 :: Declined,
2221    0x02 :: FailedDownload,
2222    0x03 :: Accepted
2223);
2224
2225proto_varint_enum!(AdvancementTabAction,
2226    0x00 :: Opened(String),
2227    0x01 :: Closed
2228);
2229
2230proto_varint_enum!(CommandBlockMode,
2231    0x00 :: Sequence,
2232    0x01 :: Auto,
2233    0x02 :: Redstone
2234);
2235
2236proto_byte_flag!(CommandBlockFlags,
2237    0x01 :: is_track_output set_track_output,
2238    0x02 :: is_conditional set_conditional,
2239    0x04 :: is_automatic set_automatic
2240);
2241
2242proto_varint_enum!(UpdateStructureBlockAction,
2243    0x00 :: UpdateData,
2244    0x01 :: SaveStructure,
2245    0x02 :: LoadStructure,
2246    0x03 :: DetectSize
2247);
2248
2249proto_varint_enum!(UpdateStructureBlockMode,
2250    0x00 :: Save,
2251    0x01 :: Load,
2252    0x02 :: Corner,
2253    0x03 :: Data
2254);
2255
2256proto_varint_enum!(UpdateStructureBlockMirror,
2257    0x00 :: NoMirror,
2258    0x01 :: LeftRight,
2259    0x02 :: FrontBack
2260);
2261
2262proto_varint_enum!(UpdateStructureBlockRotation,
2263    0x00 :: NoRotation,
2264    0x01 :: Clockwise90,
2265    0x02 :: Clockwise180,
2266    0x03 :: CounterClockwise90
2267);
2268
2269proto_byte_flag!(UpdateStructureBlockFlags,
2270    0x01 :: is_ignore_entities set_ignore_entities,
2271    0x02 :: is_show_air set_show_air,
2272    0x04 :: is_show_bounding_box set_show_bounding_box
2273);
2274
2275#[derive(Clone, PartialEq, Debug)]
2276pub struct RecipeSpec {
2277    pub recipe: Recipe,
2278    pub id: String,
2279}
2280
2281proto_str_enum!(Recipe,
2282    "minecraft:crafting_shapeless" :: CraftingShapeless(RecipeCraftingShapelessSpec),
2283    "minecraft:crafting_shaped" :: CraftingShaped(RecipeCraftingShapedSpec),
2284    "minecraft:crafting_special_armordye" :: CraftingArmorDye,
2285    "minecraft:crafting_special_bookcloning" :: CraftingBookCloning,
2286    "minecraft:crafting_special_mapcloning" :: CraftingMapCloning,
2287    "minecraft:crafting_special_mapextending" :: CraftingMapExtending,
2288    "minecraft:crafting_special_firework_rocket" :: CraftingFireworkRocket,
2289    "minecraft:crafting_special_firework_star" :: CraftingFireworkStar,
2290    "minecraft:crafting_special_firework_star_fade" :: CraftingFireworkStarFade,
2291    "minecraft:crafting_special_repairitem" :: CraftingRepairItem,
2292    "minecraft:crafting_special_tippedarrow" :: CraftingTippedArrow,
2293    "minecraft:crafting_special_bannerduplicate" :: CraftingBannerDuplicate,
2294    "minecraft:crafting_special_banneraddpattern" :: CraftingBannerAddPattern,
2295    "minecraft:crafting_special_shielddecoration" :: CraftingShieldDecoration,
2296    "minecraft:crafting_special_shulkerboxcoloring" :: CraftingShulkerBoxColoring,
2297    "minecraft:crafting_special_suspiciousstew" :: CraftingSuspiciousStew,
2298    "minecraft:smelting" :: Smelting(RecipeSmeltingSpec),
2299    "minecraft:blasting" :: Blasting(RecipeSmeltingSpec),
2300    "minecraft:smoking" :: Smoking(RecipeSmeltingSpec),
2301    "minecraft:campfire_cooking" :: CampfireCooking(RecipeSmeltingSpec),
2302    "minecraft:stonecutting" :: StoneCutting(RecipeStonecuttingSpec)
2303);
2304
2305impl Serialize for RecipeSpec {
2306    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
2307        let _type = self.recipe.id();
2308        to.serialize_other(&_type)?;
2309        to.serialize_other(&self.id)?;
2310        self.recipe.serialize_body(to)
2311    }
2312}
2313
2314impl Deserialize for RecipeSpec {
2315    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
2316        let Deserialized { value: _type, data } = String::mc_deserialize(data)?;
2317        let Deserialized {
2318            value: recipe_id,
2319            data,
2320        } = String::mc_deserialize(data)?;
2321
2322        Ok(Recipe::deserialize_with_id(_type.as_str(), data)?.map(move |recipe| {
2323            RecipeSpec {
2324                id: recipe_id,
2325                recipe,
2326            }
2327        }))
2328    }
2329}
2330
2331#[cfg(all(test, feature = "std"))]
2332impl TestRandom for RecipeSpec {
2333    fn test_gen_random() -> Self {
2334        RecipeSpec {
2335            recipe: Recipe::test_gen_random(),
2336            id: String::test_gen_random(),
2337        }
2338    }
2339}
2340
2341proto_struct!(RecipeIngredient {
2342    items: CountedArray<Slot, VarInt>
2343});
2344
2345proto_struct!(RecipeCraftingShapelessSpec {
2346    group: String,
2347    ingredients: CountedArray<RecipeIngredient, VarInt>,
2348    result: Slot
2349});
2350
2351#[derive(Debug, Clone, PartialEq)]
2352pub struct RecipeCraftingShapedSpec {
2353    pub width: VarInt,
2354    pub height: VarInt,
2355    pub group: String,
2356    pub ingredients: Vec<RecipeIngredient>,
2357    pub result: Slot,
2358}
2359
2360impl Serialize for RecipeCraftingShapedSpec {
2361    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
2362        to.serialize_other(&self.width)?;
2363        to.serialize_other(&self.height)?;
2364        to.serialize_other(&self.group)?;
2365        for elem in &self.ingredients {
2366            to.serialize_other(elem)?;
2367        }
2368        to.serialize_other(&self.result)?;
2369        Ok(())
2370    }
2371}
2372
2373impl Deserialize for RecipeCraftingShapedSpec {
2374    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
2375        let Deserialized { value: width, data } = <VarInt>::mc_deserialize(data)?;
2376        let Deserialized { value: height, data } = <VarInt>::mc_deserialize(data)?;
2377        let Deserialized { value: group, mut data } = <String>::mc_deserialize(data)?;
2378
2379        let ingredients_count = width.0 as usize * height.0 as usize;
2380        let mut ingredients: Vec<RecipeIngredient> = Vec::with_capacity(ingredients_count);
2381        for _ in 0..ingredients_count {
2382            let Deserialized { value: elem, data: rest } = RecipeIngredient::mc_deserialize(data)?;
2383            data = rest;
2384            ingredients.push(elem);
2385        }
2386
2387        let Deserialized { value: result, data } = Slot::mc_deserialize(data)?;
2388
2389        Deserialized::ok(
2390            Self {
2391                width,
2392                height,
2393                group,
2394                ingredients,
2395                result,
2396            },
2397            data,
2398        )
2399    }
2400}
2401
2402#[cfg(all(test, feature = "std"))]
2403impl TestRandom for RecipeCraftingShapedSpec {
2404    fn test_gen_random() -> Self {
2405        use rand::distributions::Distribution;
2406        let size_distr = rand::distributions::Uniform::new(1, 9);
2407        let mut rng = rand::thread_rng();
2408
2409        let width: VarInt = size_distr.sample(&mut rng).into();
2410        let height: VarInt = size_distr.sample(&mut rng).into();
2411        let n_ingredients = (width.0 as usize) * (height.0 as usize);
2412        let mut ingredients = Vec::with_capacity(n_ingredients);
2413        for _ in 0..n_ingredients {
2414            ingredients.push(RecipeIngredient::test_gen_random());
2415        }
2416
2417        RecipeCraftingShapedSpec {
2418            width,
2419            height,
2420            group: String::test_gen_random(),
2421            ingredients,
2422            result: Some(ItemStack::test_gen_random()),
2423        }
2424    }
2425}
2426
2427proto_struct!(RecipeSmeltingSpec {
2428    group: String,
2429    ingredient: RecipeIngredient,
2430    result: Slot,
2431    experience: f32,
2432    cooking_time: VarInt
2433});
2434
2435proto_struct!(RecipeStonecuttingSpec {
2436    group: String,
2437    ingredient: RecipeIngredient,
2438    result: Slot
2439});
2440
2441proto_varint_enum!(RecipeUnlockAction,
2442    0x00 :: Init,
2443    0x01 :: Add,
2444    0x02 :: Remove
2445);
2446
2447#[derive(Clone, PartialEq, Debug)]
2448pub struct ChunkData {
2449    pub position: ChunkPosition<i32>,
2450    pub primary_bit_mask: VarInt,
2451    pub heightmaps: NamedNbtTag,
2452    pub biomes: Option<Box<[i32; 1024]>>,
2453    pub data: CountedArray<u8, VarInt>,
2454    pub block_entities: Vec<NamedNbtTag>,
2455}
2456
2457impl Serialize for ChunkData {
2458    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
2459        to.serialize_other(&self.position)?;
2460        let full_chunk = self.biomes.is_some();
2461        to.serialize_other(&full_chunk)?;
2462        to.serialize_other(&self.primary_bit_mask)?;
2463        to.serialize_other(&self.heightmaps)?;
2464
2465        if full_chunk {
2466            let biomes = self.biomes.as_ref().unwrap();
2467            for elem in biomes.iter() {
2468                to.serialize_other(elem)?;
2469            }
2470        }
2471
2472        to.serialize_other(&self.data)?;
2473        let num_block_entities = VarInt(self.block_entities.len() as i32);
2474        to.serialize_other(&num_block_entities)?;
2475        for entity in &self.block_entities {
2476            to.serialize_other(entity)?;
2477        }
2478
2479        Ok(())
2480    }
2481}
2482
2483impl Deserialize for ChunkData {
2484    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
2485        let Deserialized { value: position, data } = <ChunkPosition<i32>>::mc_deserialize(data)?;
2486        let Deserialized { value: is_full_chunk, data } = bool::mc_deserialize(data)?;
2487        let Deserialized { value: primary_bit_mask, data } = VarInt::mc_deserialize(data)?;
2488        let Deserialized { value: heightmaps, mut data } = NamedNbtTag::mc_deserialize(data)?;
2489        let biomes = if is_full_chunk {
2490            let mut biomes: [i32; 1024] = [0i32; 1024];
2491            for elem in &mut biomes {
2492                let Deserialized { value, data: rest } = i32::mc_deserialize(data)?;
2493                data = rest;
2494                *elem = value;
2495            }
2496            Some(biomes)
2497        } else {
2498            None
2499        };
2500        let Deserialized { value: chunk_data, data } = <CountedArray<u8, VarInt>>::mc_deserialize(data)?;
2501        let Deserialized { value: n_block_entities_raw, mut data } = VarInt::mc_deserialize(data)?;
2502        let n_block_entities = n_block_entities_raw.0 as usize;
2503        let mut block_entities = Vec::with_capacity(n_block_entities);
2504        for _ in 0..n_block_entities {
2505            let Deserialized { value: entity, data: rest } = NamedNbtTag::mc_deserialize(data)?;
2506            data = rest;
2507            block_entities.push(entity);
2508        }
2509
2510        Deserialized::ok(ChunkData {
2511            position,
2512            primary_bit_mask,
2513            heightmaps,
2514            biomes: biomes.map(move |b| Box::new(b)),
2515            data: chunk_data,
2516            block_entities,
2517        }, data)
2518    }
2519}
2520
2521#[cfg(all(test, feature = "std"))]
2522impl TestRandom for ChunkData {
2523    fn test_gen_random() -> Self {
2524        ChunkData {
2525            position: <ChunkPosition<i32>>::test_gen_random(),
2526            primary_bit_mask: VarInt::test_gen_random(),
2527            heightmaps: NamedNbtTag::test_gen_random(),
2528            biomes: None,
2529            data: <CountedArray<u8, VarInt>>::test_gen_random(),
2530            block_entities: vec![],
2531        }
2532    }
2533}
2534
2535pub const LIGHT_DATA_LENGTH: usize = 2048;
2536pub const LIGHT_DATA_SECTIONS: usize = 18;
2537
2538#[derive(Clone, PartialEq)]
2539pub struct LightingData {
2540    pub data: Box<[Option<[u8; LIGHT_DATA_LENGTH]>; LIGHT_DATA_SECTIONS]>,
2541}
2542
2543impl LightingData {
2544    fn deserialize(update_mask: VarInt, mut data: &[u8]) -> DeserializeResult<Self> {
2545        let mut out = Box::new([None; LIGHT_DATA_SECTIONS]);
2546        for i in 0..LIGHT_DATA_SECTIONS {
2547            // gotta read the var int
2548            if update_mask.0 & (1 << i) != 0 {
2549                let Deserialized { value: length, data: rest } = VarInt::mc_deserialize(data)?;
2550                if (length.0 as usize) != LIGHT_DATA_LENGTH {
2551                    return Err(DeserializeErr::CannotUnderstandValue(alloc::format!("bad data length in light update {}", length)));
2552                }
2553
2554                data = rest;
2555                if data.len() < LIGHT_DATA_LENGTH {
2556                    return Err(DeserializeErr::Eof);
2557                }
2558
2559                let (section, rest) = data.split_at(LIGHT_DATA_LENGTH);
2560                let mut to_vec = [0u8; LIGHT_DATA_LENGTH];
2561                to_vec.copy_from_slice(section);
2562                out[i] = Some(to_vec);
2563                data = rest;
2564            }
2565        }
2566
2567        let result = Self {
2568            data: out,
2569        };
2570
2571        Deserialized::ok(result, data)
2572    }
2573
2574    fn update_mask(&self) -> VarInt {
2575        self.compute_has_mask(true)
2576    }
2577
2578    fn reset_mask(&self) -> VarInt {
2579        self.compute_has_mask(false)
2580    }
2581
2582    fn compute_has_mask(&self, has: bool) -> VarInt {
2583        let mut out: u32 = 0;
2584        for i in 0..LIGHT_DATA_SECTIONS {
2585            if self.data[i].is_some() == has {
2586                out |= 1 << i;
2587            }
2588        }
2589
2590        VarInt(out as i32)
2591    }
2592
2593    fn serialize_data<S: Serializer>(&self, to: &mut S) -> SerializeResult {
2594        for item in self.data.iter() {
2595            if let Some(contents) = item {
2596                to.serialize_other(&VarInt(2048))?;
2597                to.serialize_bytes(&contents[..])?;
2598            }
2599        }
2600
2601        Ok(())
2602    }
2603}
2604
2605impl fmt::Debug for LightingData {
2606    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2607        write!(
2608            f,
2609            "LightingData(update={:018b}, reset={:018b}, size={}, bytes={})",
2610            self.update_mask().0,
2611            self.reset_mask().0,
2612            self.data.iter().filter(move |v| v.is_some()).count(),
2613            self.data.iter()
2614                .filter_map(move |v| v.
2615                    map(move |arr| arr.len()))
2616                .sum::<usize>())
2617    }
2618}
2619
2620impl fmt::Display for LightingData {
2621    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2622        <dyn fmt::Debug>::fmt(self, f)
2623    }
2624}
2625
2626#[cfg(all(test, feature = "std"))]
2627impl LightingData {
2628    fn gen_random_mask() -> i32 {
2629        let rand: u32 = rand::random();
2630        (rand & ((1 << 19) - 1)) as i32
2631    }
2632}
2633
2634#[cfg(all(test, feature = "std"))]
2635impl TestRandom for LightingData {
2636    fn test_gen_random() -> Self {
2637        let set_mask = Self::gen_random_mask();
2638        let mut data = Box::new([None; LIGHT_DATA_SECTIONS]);
2639        for i in 0..LIGHT_DATA_SECTIONS {
2640            if (set_mask & (1 << i)) != 0 {
2641                let mut data_arr = [0u8; LIGHT_DATA_LENGTH];
2642                for k in 0..LIGHT_DATA_LENGTH {
2643                    data_arr[k] = rand::random();
2644                }
2645                data[i] = Some(data_arr);
2646            }
2647        }
2648
2649        Self {
2650            data,
2651        }
2652    }
2653}
2654
2655#[derive(Clone, PartialEq, Debug)]
2656pub struct LightingUpdateSpec {
2657    pub skylight_data: LightingData,
2658    pub blocklight_data: LightingData,
2659}
2660
2661impl Serialize for LightingUpdateSpec {
2662    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
2663        self.skylight_data.update_mask().mc_serialize(to)?;
2664        self.blocklight_data.update_mask().mc_serialize(to)?;
2665        self.skylight_data.reset_mask().mc_serialize(to)?;
2666        self.blocklight_data.reset_mask().mc_serialize(to)?;
2667        self.skylight_data.serialize_data(to)?;
2668        self.blocklight_data.serialize_data(to)
2669    }
2670}
2671
2672impl Deserialize for LightingUpdateSpec {
2673    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
2674        let Deserialized { value: skylight_update_mask, data } = VarInt::mc_deserialize(data)?;
2675        let Deserialized { value: blocklight_update_mask, data } = VarInt::mc_deserialize(data)?;
2676        let Deserialized { value: _, data } = VarInt::mc_deserialize(data)?;
2677        let Deserialized { value: _, data } = VarInt::mc_deserialize(data)?;
2678
2679        let Deserialized { value: skylight_data, data } = LightingData::deserialize(skylight_update_mask, data)?;
2680        let Deserialized { value: blocklight_data, data } = LightingData::deserialize(blocklight_update_mask, data)?;
2681
2682        Deserialized::ok(Self {
2683            skylight_data,
2684            blocklight_data,
2685        }, data)
2686    }
2687}
2688
2689#[cfg(all(test, feature = "std"))]
2690impl TestRandom for LightingUpdateSpec {
2691    fn test_gen_random() -> Self {
2692        Self {
2693            skylight_data: LightingData::test_gen_random(),
2694            blocklight_data: LightingData::test_gen_random(),
2695        }
2696    }
2697}
2698
2699#[derive(Clone, Debug, PartialEq, Default)]
2700pub struct EntityMetadata {
2701    pub fields: Vec<EntityMetadataField>
2702}
2703
2704impl Serialize for EntityMetadata {
2705    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
2706        for field in &self.fields {
2707            to.serialize_byte(field.index)?;
2708            to.serialize_other(&field.data)?;
2709        }
2710        to.serialize_byte(0xFF)
2711    }
2712}
2713
2714impl Deserialize for EntityMetadata {
2715    fn mc_deserialize(mut data: &[u8]) -> DeserializeResult<'_, Self> {
2716        let mut fields = Vec::new();
2717        loop {
2718            let Deserialized { value: index, data: rest } = u8::mc_deserialize(data)?;
2719            data = rest;
2720            if index == 0xFF {
2721                break;
2722            }
2723
2724            let Deserialized { value: field, data: rest } = EntityMetadataFieldData::mc_deserialize(data)?;
2725            data = rest;
2726            fields.push(EntityMetadataField{
2727                index,
2728                data: field,
2729            });
2730        }
2731
2732        Deserialized::ok(Self{
2733            fields,
2734        }, data)
2735    }
2736}
2737
2738#[cfg(all(test, feature = "std"))]
2739impl TestRandom for EntityMetadata {
2740    fn test_gen_random() -> Self {
2741        let n_fields = rand::random::<usize>() % 10;
2742        let mut fields = Vec::with_capacity(n_fields);
2743        for i in 0..n_fields {
2744            fields.push(EntityMetadataField{
2745                index: i as u8,
2746                data: EntityMetadataFieldData::test_gen_random(),
2747            });
2748        }
2749
2750        Self {
2751            fields,
2752        }
2753    }
2754}
2755
2756impl EntityMetadata {
2757    pub fn set(&mut self, index: u8, data: EntityMetadataFieldData) {
2758        for field in &mut self.fields {
2759            if field.index == index {
2760                field.data = data;
2761                return;
2762            }
2763        }
2764
2765        self.fields.push(EntityMetadataField{
2766            index,
2767            data,
2768        })
2769    }
2770
2771    pub fn remove(&mut self, index: u8) -> bool {
2772        for i in 0..self.fields.len() {
2773            let field = self.fields
2774                .get(i)
2775                .expect("iterating through this vec, definitely have this index");
2776            if field.index == index {
2777                self.fields.remove(i);
2778                return true;
2779            }
2780        }
2781
2782        false
2783    }
2784
2785    pub fn get(&self, index: u8) -> Option<&EntityMetadataFieldData> {
2786        for field in &self.fields {
2787            if field.index == index {
2788                return Some(&field.data);
2789            }
2790        }
2791
2792        None
2793    }
2794
2795    pub fn get_mut(&mut self, index: u8) -> Option<&mut EntityMetadataFieldData> {
2796        for field in &mut self.fields {
2797            if field.index == index {
2798                return Some(&mut field.data);
2799            }
2800        }
2801
2802        None
2803    }
2804}
2805
2806impl<'a> core::iter::IntoIterator for &'a EntityMetadata {
2807    type Item = (u8, &'a EntityMetadataFieldData);
2808    type IntoIter = FieldIter<'a>;
2809
2810    fn into_iter(self) -> Self::IntoIter {
2811        FieldIter {
2812            data: self,
2813            at: 0,
2814        }
2815    }
2816}
2817
2818pub struct FieldIter<'a> {
2819    data: &'a EntityMetadata,
2820    at: usize
2821}
2822
2823impl<'a> core::iter::Iterator for FieldIter<'a> {
2824    type Item = (u8, &'a EntityMetadataFieldData);
2825
2826    fn next(&mut self) -> Option<Self::Item> {
2827        self.data.fields.get(self.at).map(move |field| (field.index, &field.data))
2828    }
2829
2830    fn size_hint(&self) -> (usize, Option<usize>) {
2831        let len = self.data.fields.len();
2832        (len, Some(len))
2833    }
2834}
2835
2836#[derive(Clone, Debug, PartialEq)]
2837pub struct EntityMetadataField {
2838    pub index: u8,
2839    pub data: EntityMetadataFieldData
2840}
2841
2842proto_varint_enum!(EntityMetadataFieldData,
2843    0x00 :: Byte(i8),
2844    0x01 :: VarInt(VarInt),
2845    0x02 :: Float(f32),
2846    0x03 :: String(String),
2847    0x04 :: Chat(Chat),
2848    0x05 :: OptChat(Option<Chat>),
2849    0x06 :: Slot(Slot),
2850    0x07 :: Boolean(bool),
2851    0x08 :: Rotation(Vec3<f32>),
2852    0x09 :: Position(IntPosition),
2853    0x0A :: OptPosition(Option<IntPosition>),
2854    0x0B :: Direction(EntityDirection),
2855    0x0C :: OptUUID(Option<UUID4>),
2856    0x0D :: OptBlockId(VarInt),
2857    0x0E :: NBT(NamedNbtTag),
2858    0x0F :: Particle(ParticleSpec),
2859    0x10 :: VillagerData(EntityVillagerData),
2860    0x11 :: OptVarInt(VarInt),
2861    0x12 :: Pose(EntityPose)
2862);
2863
2864proto_varint_enum!(EntityDirection,
2865    0x00 :: Down,
2866    0x01 :: Up,
2867    0x02 :: North,
2868    0x03 :: South,
2869    0x04 :: West,
2870    0x05 :: East
2871);
2872
2873proto_struct!(EntityVillagerData {
2874    villager_type: VillagerType,
2875    villager_profession: VillagerProfession,
2876    level: VarInt
2877});
2878
2879proto_varint_enum!(VillagerType,
2880    0x00 :: Desert,
2881    0x01 :: Jungle,
2882    0x02 :: Plains,
2883    0x03 :: Savanna,
2884    0x04 :: Snow,
2885    0x05 :: Swamp,
2886    0x06 :: Taiga
2887);
2888
2889proto_varint_enum!(VillagerProfession,
2890    0x00 :: None,
2891    0x01 :: Armorer,
2892    0x02 :: Butcher,
2893    0x03 :: Cartographer,
2894    0x04 :: Cleric,
2895    0x05 :: Farmer,
2896    0x06 :: Fisherman,
2897    0x07 :: Fletcher,
2898    0x08 :: LeatherWorker,
2899    0x09 :: Librarian,
2900    0x0A :: Mason,
2901    0x0B :: Nitwit,
2902    0x0C :: Shepherd,
2903    0x0D :: Toolsmith,
2904    0x0E :: Weaponsmith
2905);
2906
2907proto_varint_enum!(EntityPose,
2908    0x00 :: Standing,
2909    0x01 :: FallFlying,
2910    0x02 :: Sleeping,
2911    0x03 :: Swimming,
2912    0x04 :: SpinAttack,
2913    0x05 :: Sneaking,
2914    0x06 :: Dying
2915);
2916
2917proto_varint_enum!(ParticleSpec,
2918    0x00 :: AmbientEntityEffect,
2919    0x01 :: AngryVillager,
2920    0x02 :: Barrier,
2921    0x03 :: Block(BlockParticleData),
2922    0x04 :: Bubble,
2923    0x05 :: Cloud,
2924    0x06 :: Crit,
2925    0x07 :: DamageIndicator,
2926    0x08 :: DragonBreath,
2927    0x09 :: DrippingLava,
2928    0x0A :: FallingLava,
2929    0x0B :: LandingLava,
2930    0x0C :: DrippingWater,
2931    0x0D :: FallingWater,
2932    0x0E :: Dust(DustParticleData),
2933    0x0F :: Effect,
2934    0x10 :: ElderGuardian,
2935    0x11 :: EnchantedHit,
2936    0x12 :: Enchant,
2937    0x13 :: EndRod,
2938    0x14 :: EntityEffect,
2939    0x15 :: ExposionEmitter,
2940    0x16 :: Explosion,
2941    0x17 :: FallingDust(DustParticleData),
2942    0x18 :: Firework,
2943    0x19 :: Fishing,
2944    0x1A :: Flame,
2945    0x1B :: Flash,
2946    0x1C :: HappyVillager,
2947    0x1D :: Composter,
2948    0x1E :: Heart,
2949    0x1F :: InstantEffect,
2950    0x20 :: Item(Slot),
2951    0x21 :: ItemSlime,
2952    0x22 :: ItemSnowball,
2953    0x23 :: LargeSmoke,
2954    0x24 :: Lava,
2955    0x25 :: Mycelium,
2956    0x26 :: Note,
2957    0x27 :: Poof,
2958    0x28 :: Portal,
2959    0x29 :: Rain,
2960    0x2A :: Smoke,
2961    0x2B :: Sneeze,
2962    0x2C :: Spit,
2963    0x2D :: SquidInk,
2964    0x2E :: SweepAttack,
2965    0x2F :: TotemOfUndying,
2966    0x30 :: Underwater,
2967    0x31 :: Splash,
2968    0x32 :: Witch,
2969    0x33 :: BubblePop,
2970    0x34 :: CurrentDown,
2971    0x35 :: BubbleColumnUp,
2972    0x36 :: Nautilus,
2973    0x37 :: Dolphin,
2974    0x38 :: CampfireCosySmoke,
2975    0x39 :: CampfireSignalSmoke,
2976    0x3A :: DrippingHoney,
2977    0x3B :: FallingHoney,
2978    0x3C :: LandingHoney,
2979    0x3D :: FallingNectar
2980);
2981
2982proto_struct!(BlockParticleData {
2983    block_state: VarInt
2984});
2985
2986proto_struct!(DustParticleData {
2987    red: f32,
2988    green: f32,
2989    blue: f32,
2990    scale: f32
2991});
2992
2993#[cfg(all(test, feature = "std"))]
2994pub mod tests {
2995    use super::*;
2996    use crate::packet_test_cases;
2997
2998    packet_test_cases!(RawPacket578, Packet578, Handshake, HandshakeSpec,
2999        test_handshake, bench_write_handshake, bench_read_handshake);
3000
3001    packet_test_cases!(RawPacket578, Packet578, StatusRequest, StatusRequestSpec,
3002        test_status_request, bench_write_status_request, bench_read_status_request);
3003
3004    packet_test_cases!(RawPacket578, Packet578, StatusPing, StatusPingSpec,
3005        test_status_ping, bench_write_status_ping, bench_read_status_ping);
3006
3007    packet_test_cases!(RawPacket578, Packet578, StatusResponse, StatusResponseSpec,
3008        test_status_response, bench_write_status_response, bench_read_status_response);
3009
3010    packet_test_cases!(RawPacket578, Packet578, StatusPong, StatusPongSpec,
3011        test_status_pong, bench_write_status_pong, bench_read_status_pong);
3012
3013    packet_test_cases!(RawPacket578, Packet578, LoginDisconnect, LoginDisconnectSpec,
3014        test_login_disconnect, bench_write_login_disconnect, bench_read_login_disconnect);
3015
3016    packet_test_cases!(RawPacket578, Packet578, LoginEncryptionRequest, LoginEncryptionRequestSpec,
3017        test_login_encryption_request, bench_write_login_encryption_request, bench_read_login_encryption_request);
3018
3019    packet_test_cases!(RawPacket578, Packet578, LoginSuccess, LoginSuccessSpec,
3020        test_login_success, bench_write_login_success, bench_read_login_success);
3021
3022    packet_test_cases!(RawPacket578, Packet578, LoginSetCompression, LoginSetCompressionSpec,
3023        test_login_set_compression, bench_write_login_set_compression, bench_read_login_set_compression);
3024
3025    packet_test_cases!(RawPacket578, Packet578, LoginPluginRequest, LoginPluginRequestSpec,
3026        test_login_plugin_request, bench_write_login_plugin_request, bench_read_login_plugin_request);
3027
3028    packet_test_cases!(RawPacket578, Packet578, LoginStart, LoginStartSpec,
3029        test_login_start, bench_write_login_start, bench_read_login_start);
3030
3031    packet_test_cases!(RawPacket578, Packet578, LoginEncryptionResponse, LoginEncryptionResponseSpec,
3032        test_login_encryption_response, bench_write_login_encryption_response, bench_read_login_encryption_response);
3033
3034    packet_test_cases!(RawPacket578, Packet578, LoginPluginResponse, LoginPluginResponseSpec,
3035        test_login_plugin_response, bench_write_login_plugin_response, bench_read_login_plugin_response);
3036
3037    packet_test_cases!(RawPacket578, Packet578, PlaySpawnEntity, PlaySpawnEntitySpec,
3038        test_play_spawn_entity, bench_write_play_spawn_entity, bench_read_play_spawn_entity);
3039
3040    packet_test_cases!(RawPacket578, Packet578, PlaySpawnExperienceOrb, PlaySpawnExperienceOrbSpec,
3041        test_play_spawn_experience_orb, bench_write_play_spawn_experience_orb, bench_read_play_spawn_experience_orb);
3042
3043    packet_test_cases!(RawPacket578, Packet578, PlaySpawnWeatherEntity, PlaySpawnWeatherEntitySpec,
3044        test_play_spawn_weather_entity, bench_write_play_spawn_weather_entity, bench_read_play_spawn_weather_entity);
3045
3046    packet_test_cases!(RawPacket578, Packet578, PlaySpawnLivingEntity, PlaySpawnLivingEntitySpec,
3047        test_play_spawn_living_entity, bench_write_play_spawn_living_entity, bench_read_play_spawn_living_entity);
3048
3049    packet_test_cases!(RawPacket578, Packet578, PlaySpawnPainting, PlaySpawnPaintingSpec,
3050        test_play_spawn_painting, bench_write_play_spawn_painting, bench_read_play_spawn_painting);
3051
3052    packet_test_cases!(RawPacket578, Packet578, PlaySpawnPlayer, PlaySpawnPlayerSpec,
3053        test_play_spawn_player, bench_write_play_spawn_player, bench_read_play_spawn_player);
3054
3055    packet_test_cases!(RawPacket578, Packet578, PlayEntityAnimation, PlayEntityAnimationSpec,
3056        test_play_entity_animation, bench_write_play_entity_animation, bench_read_play_entity_animation);
3057
3058    packet_test_cases!(RawPacket578, Packet578, PlayStatistics, PlayStatisticsSpec,
3059        test_play_statistics, bench_write_play_statistics, bench_read_play_statistics);
3060
3061    packet_test_cases!(RawPacket578, Packet578, PlayAcknowledgePlayerDigging, PlayAcknowledgePlayerDiggingSpec,
3062        test_play_acknowledge_player_digging, bench_write_play_acknowledge_player_digging, bench_read_play_acknowledge_player_digging);
3063
3064    packet_test_cases!(RawPacket578, Packet578, PlayBlockBreakAnimation, PlayBlockBreakAnimationSpec,
3065        test_play_block_break_animation, bench_write_play_block_break_animation, bench_read_play_block_break_animation);
3066
3067    packet_test_cases!(RawPacket578, Packet578, PlayBlockEntityData, PlayBlockEntityDataSpec,
3068        test_play_block_entity_data, bench_write_play_block_entity_data, bench_read_play_block_entity_data);
3069
3070    packet_test_cases!(RawPacket578, Packet578, PlayBlockAction, PlayBlockActionSpec,
3071        test_play_block_action, bench_write_play_block_action, bench_read_play_block_action);
3072
3073    packet_test_cases!(RawPacket578, Packet578, PlayBlockChange, PlayBlockChangeSpec,
3074        test_play_block_change, bench_write_play_block_change, bench_read_play_block_change);
3075
3076    packet_test_cases!(RawPacket578, Packet578, PlayBossBar, PlayBossBarSpec,
3077        test_play_boss_bar, bench_write_play_boss_bar, bench_read_play_boss_bar);
3078
3079    packet_test_cases!(RawPacket578, Packet578, PlayServerDifficulty, PlayServerDifficultySpec,
3080        test_play_server_difficulty, bench_write_play_server_difficulty, bench_read_play_server_difficulty);
3081
3082    packet_test_cases!(RawPacket578, Packet578, PlayServerChatMessage, PlayServerChatMessageSpec,
3083        test_play_server_chat_message, bench_write_play_server_chat_message, bench_read_play_server_chat_message);
3084
3085    packet_test_cases!(RawPacket578, Packet578, PlayMultiBlockChange, PlayMultiBlockChangeSpec,
3086        test_play_multi_block_change, bench_write_play_multi_block_change, bench_read_play_multi_block_change);
3087
3088    packet_test_cases!(RawPacket578, Packet578, PlayTabComplete, PlayTabCompleteSpec,
3089        test_play_tab_complete, bench_write_play_tab_complete, bench_read_play_tab_complete);
3090
3091    packet_test_cases!(RawPacket578, Packet578, PlayDeclareCommands, PlayDeclareCommandsSpec,
3092        test_play_declare_commands, bench_write_play_declare_commands, bench_read_play_declare_commands);
3093
3094    packet_test_cases!(RawPacket578, Packet578, PlayServerWindowConfirmation, PlayServerWindowConfirmationSpec,
3095        test_play_server_window_confirmation, bench_write_play_server_window_confirmation, bench_read_play_server_window_confirmation);
3096
3097    packet_test_cases!(RawPacket578, Packet578, PlayServerCloseWindow, PlayServerCloseWindowSpec,
3098        test_play_server_close_window, bench_write_play_server_close_window, bench_read_play_server_close_window);
3099
3100    packet_test_cases!(RawPacket578, Packet578, PlayWindowItems, PlayWindowItemsSpec,
3101        test_play_window_items, bench_write_play_window_items, bench_read_play_window_items);
3102
3103    packet_test_cases!(RawPacket578, Packet578, PlayWindowProperty, PlayWindowPropertySpec,
3104        test_play_window_property, bench_write_play_window_property, bench_read_play_window_property);
3105
3106    packet_test_cases!(RawPacket578, Packet578, PlaySetSlot, PlaySetSlotSpec,
3107        test_play_set_slot, bench_write_play_set_slot, bench_read_play_set_slot);
3108
3109    packet_test_cases!(RawPacket578, Packet578, PlaySetCooldown, PlaySetCooldownSpec,
3110        test_play_set_cooldown, bench_write_play_set_cooldown, bench_read_play_set_cooldown);
3111
3112    packet_test_cases!(RawPacket578, Packet578, PlayServerPluginMessage, PlayServerPluginMessageSpec,
3113        test_play_server_plugin_message, bench_write_play_server_plugin_message, bench_read_play_server_plugin_message);
3114
3115    packet_test_cases!(RawPacket578, Packet578, PlayNamedSoundEffect, PlayNamedSoundEffectSpec,
3116        test_play_named_sound_effect, bench_write_play_named_sound_effect, bench_read_play_named_sound_effect);
3117
3118    packet_test_cases!(RawPacket578, Packet578, PlayDisconnect, PlayDisconnectSpec,
3119        test_play_disconnect, bench_write_play_disconnect, bench_read_play_disconnect);
3120
3121    packet_test_cases!(RawPacket578, Packet578, PlayEntityStatus, PlayEntityStatusSpec,
3122        test_play_entity_status, bench_write_play_entity_status, bench_read_play_entity_status);
3123
3124    packet_test_cases!(RawPacket578, Packet578, PlayExplosion, PlayExplosionSpec,
3125        test_play_explosion, bench_write_play_explosion, bench_read_play_explosion);
3126
3127    packet_test_cases!(RawPacket578, Packet578, PlayUnloadChunk, PlayUnloadChunkSpec,
3128        test_play_unload_chunk, bench_write_play_unload_chunk, bench_read_play_unload_chunk);
3129
3130    packet_test_cases!(RawPacket578, Packet578, PlayChangeGameState, PlayChangeGameStateSpec,
3131        test_play_change_game_state, bench_write_play_change_game_state, bench_read_play_change_game_state);
3132
3133    packet_test_cases!(RawPacket578, Packet578, PlayOpenHorseWindow, PlayOpenHorseWindowSpec,
3134        test_play_open_horse_window, bench_write_play_open_horse_window, bench_read_play_open_horse_window);
3135
3136    packet_test_cases!(RawPacket578, Packet578, PlayServerKeepAlive, PlayServerKeepAliveSpec,
3137        test_play_server_keep_alive, bench_write_play_server_keep_alive, bench_read_play_server_keep_alive);
3138
3139    packet_test_cases!(RawPacket578, Packet578, PlayChunkData, PlayChunkDataWrapper,
3140        test_play_chunk_data, bench_write_play_chunk_data, bench_read_play_chunk_data);
3141
3142    packet_test_cases!(RawPacket578, Packet578, PlayEffect, PlayEffectSpec,
3143        test_play_effect, bench_write_play_effect, bench_read_play_effect);
3144
3145    packet_test_cases!(RawPacket578, Packet578, PlayParticle, PlayParticleSpec,
3146        test_play_particle, bench_write_play_particle, bench_read_play_particle);
3147
3148    packet_test_cases!(RawPacket578, Packet578, PlayUpdateLight, PlayUpdateLightSpec,
3149        test_play_update_light, bench_write_play_update_light, bench_read_play_update_light);
3150
3151    packet_test_cases!(RawPacket578, Packet578, PlayJoinGame, PlayJoinGameSpec,
3152        test_play_join_game, bench_write_play_join_game, bench_read_play_join_game);
3153
3154    packet_test_cases!(RawPacket578, Packet578, PlayMapData, PlayMapDataSpec,
3155        test_play_map_data, bench_write_play_map_data, bench_read_play_map_data);
3156
3157    packet_test_cases!(RawPacket578, Packet578, PlayTradeList, PlayTradeListSpec,
3158        test_play_trade_list, bench_write_play_trade_list, bench_read_play_trade_list);
3159
3160    packet_test_cases!(RawPacket578, Packet578, PlayEntityPosition, PlayEntityPositionSpec,
3161        test_play_entity_position, bench_write_play_entity_position, bench_read_play_entity_position);
3162
3163    packet_test_cases!(RawPacket578, Packet578, PlayEntityPositionAndRotation, PlayEntityPositionAndRotationSpec,
3164        test_play_entity_position_and_rotation, bench_write_play_entity_position_and_rotation, bench_read_play_entity_position_and_rotation);
3165
3166    packet_test_cases!(RawPacket578, Packet578, PlayEntityRotation, PlayEntityRotationSpec,
3167        test_play_entity_rotation, bench_write_play_entity_rotation, bench_read_play_entity_rotation);
3168
3169    packet_test_cases!(RawPacket578, Packet578, PlayEntityMovement, PlayEntityMovementSpec,
3170        test_play_entity_movement, bench_write_play_entity_movement, bench_read_play_entity_movement);
3171
3172    packet_test_cases!(RawPacket578, Packet578, PlayServerVehicleMove, PlayEntityVehicleMoveSpec,
3173        test_play_server_vehicle_move, bench_write_play_server_vehicle_move, bench_read_play_server_vehicle_move);
3174
3175    packet_test_cases!(RawPacket578, Packet578, PlayOpenBook, PlayOpenBookSpec,
3176        test_play_open_book, bench_write_play_open_book, bench_read_play_open_book);
3177
3178    packet_test_cases!(RawPacket578, Packet578, PlayOpenWindow, PlayOpenWindowSpec,
3179        test_play_open_window, bench_write_play_open_window, bench_read_play_open_window);
3180
3181    packet_test_cases!(RawPacket578, Packet578, PlayOpenSignEditor, PlayOpenSignEditorSpec,
3182        test_play_open_sign_editor, bench_write_play_open_sign_editor, bench_read_play_open_sign_editor);
3183
3184    packet_test_cases!(RawPacket578, Packet578, PlayCraftRecipeResponse, PlayCraftRecipeResponseSpec,
3185        test_play_craft_recipe_response, bench_write_play_craft_recipe_response, bench_read_play_craft_recipe_response);
3186
3187    packet_test_cases!(RawPacket578, Packet578, PlayServerPlayerAbilities, PlayServerPlayerAbilitiesSpec,
3188        test_play_server_player_abilities, bench_write_play_server_player_abilities, bench_read_play_server_player_abilities);
3189
3190    packet_test_cases!(RawPacket578, Packet578, PlayCombatEvent, PlayCombatEventSpec,
3191        test_play_combat_event, bench_write_play_combat_event, bench_read_play_combat_event);
3192
3193    packet_test_cases!(RawPacket578, Packet578, PlayPlayerInfo, PlayPlayerInfoSpec,
3194        test_play_player_info, bench_write_play_player_info, bench_read_play_player_info);
3195
3196    packet_test_cases!(RawPacket578, Packet578, PlayFacePlayer, PlayFacePlayerSpec,
3197        test_play_face_player, bench_write_play_face_player, bench_read_play_face_player);
3198
3199    packet_test_cases!(RawPacket578, Packet578, PlayServerPlayerPositionAndLook, PlayServerPlayerPositionAndLookSpec,
3200        test_play_server_player_position_and_look, bench_write_play_server_player_position_and_look, bench_read_play_server_player_position_and_look);
3201
3202    packet_test_cases!(RawPacket578, Packet578, PlayUnlockRecipes, PlayUnlockRecipesSpec,
3203        test_play_unlock_recipes, bench_write_play_unlock_recipes, bench_read_play_unlock_recipes);
3204
3205    packet_test_cases!(RawPacket578, Packet578, PlayDestroyEntities, PlayDestroyEntitiesSpec,
3206        test_play_destroy_entities, bench_write_play_destroy_entities, bench_read_play_destroy_entities);
3207
3208    packet_test_cases!(RawPacket578, Packet578, PlayRemoveEntityEffect, PlayRemoveEntityEffectSpec,
3209        test_play_remove_entity_effect, bench_write_play_remove_entity_effect, bench_read_play_remove_entity_effect);
3210
3211    packet_test_cases!(RawPacket578, Packet578, PlayResourcePackSend, PlayResourcePackSendSpec,
3212        test_play_resource_pack_send, bench_write_play_resource_pack_send, bench_read_play_resource_pack_send);
3213
3214    packet_test_cases!(RawPacket578, Packet578, PlayRespawn, PlayRespawnSpec,
3215        test_play_respawn, bench_write_play_respawn, bench_read_play_respawn);
3216
3217    packet_test_cases!(RawPacket578, Packet578, PlayEntityHeadLook, PlayEntityHeadLookSpec,
3218        test_play_entity_head_look, bench_write_play_entity_head_look, bench_read_play_entity_head_look);
3219
3220    packet_test_cases!(RawPacket578, Packet578, PlaySelectAdvancementTab, PlaySelectAdvancementTabSpec,
3221        test_play_select_advancement_tab, bench_write_play_select_advancement_tab, bench_read_play_select_advancement_tab);
3222
3223    packet_test_cases!(RawPacket578, Packet578, PlayWorldBorder, PlayWorldBorderSpec,
3224        test_play_world_border, bench_write_play_world_border, bench_read_play_world_border);
3225
3226    packet_test_cases!(RawPacket578, Packet578, PlayCamera, PlayCameraSpec,
3227        test_play_camera, bench_write_play_camera, bench_read_play_camera);
3228
3229    packet_test_cases!(RawPacket578, Packet578, PlayServerHeldItemChange, PlayServerHeldItemChangeSpec,
3230        test_play_server_held_item_change, bench_write_play_server_held_item_change, bench_read_play_server_held_item_change);
3231
3232    packet_test_cases!(RawPacket578, Packet578, PlayUpdateViewPosition, PlayUpdateViewPositionSpec,
3233        test_play_update_view_position, bench_write_play_update_view_position, bench_read_play_update_view_position);
3234
3235    packet_test_cases!(RawPacket578, Packet578, PlayUpdateViewDistance, PlayUpdateViewDistanceSpec,
3236        test_play_update_view_distance, bench_write_play_update_view_distance, bench_read_play_update_view_distance);
3237
3238    packet_test_cases!(RawPacket578, Packet578, PlayDisplayScoreboard, PlayDisplayScoreboardSpec,
3239        test_play_display_scoreboard, bench_write_play_display_scoreboard, bench_read_play_display_scoreboard);
3240
3241    packet_test_cases!(RawPacket578, Packet578, PlayEntityMetadata, PlayEntityMetadataSpec,
3242        test_play_entity_metadata, bench_write_play_entity_metadata, bench_read_play_entity_metadata);
3243
3244    packet_test_cases!(RawPacket578, Packet578, PlayAttachEntity, PlayAttachEntitySpec,
3245        test_play_attach_entity, bench_write_play_attach_entity, bench_read_play_attach_entity);
3246
3247    packet_test_cases!(RawPacket578, Packet578, PlayEntityVelocity, PlayEntityVelocitySpec,
3248        test_play_entity_velocity, bench_write_play_entity_velocity, bench_read_play_entity_velocity);
3249
3250    packet_test_cases!(RawPacket578, Packet578, PlayEntityEquipment, PlayEntityEquiptmentSpec,
3251        test_play_entity_equipment, bench_write_play_entity_equipment, bench_read_play_entity_equipment);
3252
3253    packet_test_cases!(RawPacket578, Packet578, PlaySetExperience, PlaySetExperienceSpec,
3254        test_play_set_experience, bench_write_play_set_experience, bench_read_play_set_experience);
3255
3256    packet_test_cases!(RawPacket578, Packet578, PlayUpdatehealth, PlayUpdateHealthSpec,
3257        test_play_updatehealth, bench_write_play_updatehealth, bench_read_play_updatehealth);
3258
3259    packet_test_cases!(RawPacket578, Packet578, PlayScoreboardObjective, PlayScoreboardObjectiveSpec,
3260        test_play_scoreboard_objective, bench_write_play_scoreboard_objective, bench_read_play_scoreboard_objective);
3261
3262    packet_test_cases!(RawPacket578, Packet578, PlaySetPassengers, PlaySetPassengersSpec,
3263        test_play_set_passengers, bench_write_play_set_passengers, bench_read_play_set_passengers);
3264
3265    packet_test_cases!(RawPacket578, Packet578, PlayTeams, PlayTeamsSpec,
3266        test_play_teams, bench_write_play_teams, bench_read_play_teams);
3267
3268    packet_test_cases!(RawPacket578, Packet578, PlayUpdateScore, PlayUpdateScoreSpec,
3269        test_play_update_score, bench_write_play_update_score, bench_read_play_update_score);
3270
3271    packet_test_cases!(RawPacket578, Packet578, PlaySpawnPosition, PlaySpawnPositionSpec,
3272        test_play_spawn_position, bench_write_play_spawn_position, bench_read_play_spawn_position);
3273
3274    packet_test_cases!(RawPacket578, Packet578, PlayTimeUpdate, PlayTimeUpdateSpec,
3275        test_play_time_update, bench_write_play_time_update, bench_read_play_time_update);
3276
3277    packet_test_cases!(RawPacket578, Packet578, PlayTitle, PlayTitleSpec,
3278        test_play_title, bench_write_play_title, bench_read_play_title);
3279
3280    packet_test_cases!(RawPacket578, Packet578, PlayEntitySoundEffect, PlayEntitySoundEffectSpec,
3281        test_play_entity_sound_effect, bench_write_play_entity_sound_effect, bench_read_play_entity_sound_effect);
3282
3283    packet_test_cases!(RawPacket578, Packet578, PlaySoundEffect, PlaySoundEffectSpec,
3284        test_play_sound_effect, bench_write_play_sound_effect, bench_read_play_sound_effect);
3285
3286    packet_test_cases!(RawPacket578, Packet578, PlayStopSound, PlayStopSoundSpec,
3287        test_play_stop_sound, bench_write_play_stop_sound, bench_read_play_stop_sound);
3288
3289    packet_test_cases!(RawPacket578, Packet578, PlayerPlayerListHeaderAndFooter, PlayPlayerListHeaderAndFooterSpec,
3290        test_player_player_list_header_and_footer, bench_write_player_player_list_header_and_footer, bench_read_player_player_list_header_and_footer);
3291
3292    packet_test_cases!(RawPacket578, Packet578, PlayNbtQueryResponse, PlayNbtQueryResponseSpec,
3293        test_play_nbt_query_response, bench_write_play_nbt_query_response, bench_read_play_nbt_query_response);
3294
3295    packet_test_cases!(RawPacket578, Packet578, PlayCollectItem, PlayCollectItemSpec,
3296        test_play_collect_item, bench_write_play_collect_item, bench_read_play_collect_item);
3297
3298    packet_test_cases!(RawPacket578, Packet578, PlayEntityTeleport, PlayEntityTeleportSpec,
3299        test_play_entity_teleport, bench_write_play_entity_teleport, bench_read_play_entity_teleport);
3300
3301    packet_test_cases!(RawPacket578, Packet578, PlayAdvancements, PlayAdvancementsSpec,
3302        test_play_advancements, bench_write_play_advancements, bench_read_play_advancements);
3303
3304    packet_test_cases!(RawPacket578, Packet578, PlayEntityProperties, PlayEntityPropertiesSpec,
3305        test_play_entity_properties, bench_write_play_entity_properties, bench_read_play_entity_properties);
3306
3307    packet_test_cases!(RawPacket578, Packet578, PlayEntityEffect, PlayEntityEffectSpec,
3308        test_play_entity_effect, bench_write_play_entity_effect, bench_read_play_entity_effect);
3309
3310    packet_test_cases!(RawPacket578, Packet578, PlayDeclareRecipes, PlayDeclareRecipesSpec,
3311        test_play_declare_recipes, bench_write_play_declare_recipes, bench_read_play_declare_recipes);
3312
3313    packet_test_cases!(RawPacket578, Packet578, PlayTags, PlayTagsSpec,
3314        test_play_tags, bench_write_play_tags, bench_read_play_tags);
3315
3316    packet_test_cases!(RawPacket578, Packet578, PlayTeleportConfirm, PlayTeleportConfirmSpec,
3317        test_play_teleport_confirm, bench_write_play_teleport_confirm, bench_read_play_teleport_confirm);
3318
3319    packet_test_cases!(RawPacket578, Packet578, PlayQueryBlockNbt, PlayQueryBlockNbtSpec,
3320        test_play_query_block_nbt, bench_write_play_query_block_nbt, bench_read_play_query_block_nbt);
3321
3322    packet_test_cases!(RawPacket578, Packet578, PlayQueryEntityNbt, PlayQueryEntityNbtSpec,
3323        test_play_query_entity_nbt, bench_write_play_query_entity_nbt, bench_read_play_query_entity_nbt);
3324
3325    packet_test_cases!(RawPacket578, Packet578, PlaySetDifficulty, PlaySetDifficultySpec,
3326        test_play_set_difficulty, bench_write_play_set_difficulty, bench_read_play_set_difficulty);
3327
3328    packet_test_cases!(RawPacket578, Packet578, PlayClientChatMessage, PlayClientChatMessageSpec,
3329        test_play_client_chat_message, bench_write_play_client_chat_message, bench_read_play_client_chat_message);
3330
3331    packet_test_cases!(RawPacket578, Packet578, PlayClientStatus, PlayClientStatusSpec,
3332        test_play_client_status, bench_write_play_client_status, bench_read_play_client_status);
3333
3334    packet_test_cases!(RawPacket578, Packet578, PlayClientSettings, PlayClientSettingsSpec,
3335        test_play_client_settings, bench_write_play_client_settings, bench_read_play_client_settings);
3336
3337    packet_test_cases!(RawPacket578, Packet578, PlayClientTabComplete, PlayClientTabCompleteSpec,
3338        test_play_client_tab_complete, bench_write_play_client_tab_complete, bench_read_play_client_tab_complete);
3339
3340    packet_test_cases!(RawPacket578, Packet578, PlayClientWindowConfirmation, PlayClientWindowConfirmationSpec,
3341        test_play_client_window_confirmation, bench_write_play_client_window_confirmation, bench_read_play_client_window_confirmation);
3342
3343    packet_test_cases!(RawPacket578, Packet578, PlayClickWindowButton, PlayClickWindowButtonSpec,
3344        test_play_click_window_button, bench_write_play_click_window_button, bench_read_play_click_window_button);
3345
3346    packet_test_cases!(RawPacket578, Packet578, PlayClickWindow, PlayClickWindowSpec,
3347        test_play_click_window, bench_write_play_click_window, bench_read_play_click_window);
3348
3349    packet_test_cases!(RawPacket578, Packet578, PlayClientCloseWindow, PlayClientCloseWindowSpec,
3350        test_play_client_close_window, bench_write_play_client_close_window, bench_read_play_client_close_window);
3351
3352    packet_test_cases!(RawPacket578, Packet578, PlayClientPluginMessage, PlayClientPluginMessageSpec,
3353        test_play_client_plugin_message, bench_write_play_client_plugin_message, bench_read_play_client_plugin_message);
3354
3355    packet_test_cases!(RawPacket578, Packet578, PlayEditBook, PlayEditBookSpec,
3356        test_play_edit_book, bench_write_play_edit_book, bench_read_play_edit_book);
3357
3358    packet_test_cases!(RawPacket578, Packet578, PlayInteractEntity, PlayInteractEntitySpec,
3359        test_play_interact_entity, bench_write_play_interact_entity, bench_read_play_interact_entity);
3360
3361    packet_test_cases!(RawPacket578, Packet578, PlayClientKeepAlive, PlayClientKeepAliveSpec,
3362        test_play_client_keep_alive, bench_write_play_client_keep_alive, bench_read_play_client_keep_alive);
3363
3364    packet_test_cases!(RawPacket578, Packet578, PlayLockDifficulty, PlayLockDifficultySpec,
3365        test_play_lock_difficulty, bench_write_play_lock_difficulty, bench_read_play_lock_difficulty);
3366
3367    packet_test_cases!(RawPacket578, Packet578, PlayPlayerPosition, PlayPlayerPositionSpec,
3368        test_play_player_position, bench_write_play_player_position, bench_read_play_player_position);
3369
3370    packet_test_cases!(RawPacket578, Packet578, PlayClientPlayerPositionAndRotation, PlayClientPlayerPositionAndRotationSpec,
3371        test_play_client_player_position_and_rotation, bench_write_play_client_player_position_and_rotation, bench_read_play_client_player_position_and_rotation);
3372
3373    packet_test_cases!(RawPacket578, Packet578, PlayPlayerRotation, PlayPlayerRotationSpec,
3374        test_play_player_rotation, bench_write_play_player_rotation, bench_read_play_player_rotation);
3375
3376    packet_test_cases!(RawPacket578, Packet578, PlayPlayerMovement, PlayPlayerMovementSpec,
3377        test_play_player_movement, bench_write_play_player_movement, bench_read_play_player_movement);
3378
3379    packet_test_cases!(RawPacket578, Packet578, PlayClientVehicleMove, PlayClientVehicleMoveSpec,
3380        test_play_client_vehicle_move, bench_write_play_client_vehicle_move, bench_read_play_client_vehicle_move);
3381
3382    packet_test_cases!(RawPacket578, Packet578, PlaySteerBoat, PlaySteerBoatSpec,
3383        test_play_steer_boat, bench_write_play_steer_boat, bench_read_play_steer_boat);
3384
3385    packet_test_cases!(RawPacket578, Packet578, PlayPickItem, PlayPickItemSpec,
3386        test_play_pick_item, bench_write_play_pick_item, bench_read_play_pick_item);
3387
3388    packet_test_cases!(RawPacket578, Packet578, PlayCraftRecipeRequest, PlayCraftRecipeRequestSpec,
3389        test_play_craft_recipe_request, bench_write_play_craft_recipe_request, bench_read_play_craft_recipe_request);
3390
3391    packet_test_cases!(RawPacket578, Packet578, PlayClientPlayerAbilities, PlayClientPlayerAbilitiesSpec,
3392        test_play_client_player_abilities, bench_write_play_client_player_abilities, bench_read_play_client_player_abilities);
3393
3394    packet_test_cases!(RawPacket578, Packet578, PlayPlayerDigging, PlayPlayerDiggingSpec,
3395        test_play_player_digging, bench_write_play_player_digging, bench_read_play_player_digging);
3396
3397    packet_test_cases!(RawPacket578, Packet578, PlayEntityAction, PlayEntityActionSpec,
3398        test_play_entity_action, bench_write_play_entity_action, bench_read_play_entity_action);
3399
3400    packet_test_cases!(RawPacket578, Packet578, PlaySteerVehicle, PlaySteerVehicleSpec,
3401        test_play_steer_vehicle, bench_write_play_steer_vehicle, bench_read_play_steer_vehicle);
3402
3403    packet_test_cases!(RawPacket578, Packet578, PlayRecipeBookData, PlayRecipeBookDataSpec,
3404        test_play_recipe_book_data, bench_write_play_recipe_book_data, bench_read_play_recipe_book_data);
3405
3406    packet_test_cases!(RawPacket578, Packet578, PlayNameItem, PlayNameItemSpec,
3407        test_play_name_item, bench_write_play_name_item, bench_read_play_name_item);
3408
3409    packet_test_cases!(RawPacket578, Packet578, PlayResourcePackStatus, PlayResourcePackStatusSpec,
3410        test_play_resource_pack_status, bench_write_play_resource_pack_status, bench_read_play_resource_pack_status);
3411
3412    packet_test_cases!(RawPacket578, Packet578, PlayAdvancementTab, PlayAdvancementTabSpec,
3413        test_play_advancement_tab, bench_write_play_advancement_tab, bench_read_play_advancement_tab);
3414
3415    packet_test_cases!(RawPacket578, Packet578, PlaySelectTrade, PlaySelectTradeSpec,
3416        test_play_select_trade, bench_write_play_select_trade, bench_read_play_select_trade);
3417
3418    packet_test_cases!(RawPacket578, Packet578, PlaySetBeaconEffect, PlaySetBeaconEffectSpec,
3419        test_play_set_beacon_effect, bench_write_play_set_beacon_effect, bench_read_play_set_beacon_effect);
3420
3421    packet_test_cases!(RawPacket578, Packet578, PlayClientHeldItemChange, PlayClientHeldItemChangeSpec,
3422        test_play_client_held_item_change, bench_write_play_client_held_item_change, bench_read_play_client_held_item_change);
3423
3424    packet_test_cases!(RawPacket578, Packet578, PlayUpdateCommandBlock, PlayUpdateCommandBlockSpec,
3425        test_play_update_command_block, bench_write_play_update_command_block, bench_read_play_update_command_block);
3426
3427    packet_test_cases!(RawPacket578, Packet578, PlayUpdateCommandBlockMinecart, PlayUpdateCommandBlockMinecartSpec,
3428        test_play_update_command_block_minecart, bench_write_play_update_command_block_minecart, bench_read_play_update_command_block_minecart);
3429
3430    packet_test_cases!(RawPacket578, Packet578, PlayCreativeInventoryAction, PlayCreativeInventoryActionSpec,
3431        test_play_creative_inventory_action, bench_write_play_creative_inventory_action, bench_read_play_creative_inventory_action);
3432
3433    packet_test_cases!(RawPacket578, Packet578, PlayUpdateJigsawBlock, PlayUpdateJigsawBlockSpec,
3434        test_play_update_jigsaw_block, bench_write_play_update_jigsaw_block, bench_read_play_update_jigsaw_block);
3435
3436    packet_test_cases!(RawPacket578, Packet578, PlayUpdateStructureBlock, PlayUpdateStructureBlockSpec,
3437        test_play_update_structure_block, bench_write_play_update_structure_block, bench_read_play_update_structure_block);
3438
3439    packet_test_cases!(RawPacket578, Packet578, PlayUpdateSign, PlayUpdateSignSpec,
3440        test_play_update_sign, bench_write_play_update_sign, bench_read_play_update_sign);
3441
3442    packet_test_cases!(RawPacket578, Packet578, PlayClientAnimation, PlayClientAnimationSpec,
3443        test_play_client_animation, bench_write_play_client_animation, bench_read_play_client_animation);
3444
3445    packet_test_cases!(RawPacket578, Packet578, PlaySpectate, PlaySpectateSpec,
3446        test_play_spectate, bench_write_play_spectate, bench_read_play_spectate);
3447
3448    packet_test_cases!(RawPacket578, Packet578, PlayBlockPlacement, PlayBlockPlacementSpec,
3449        test_play_block_placement, bench_write_play_block_placement, bench_read_play_block_placement);
3450
3451    packet_test_cases!(RawPacket578, Packet578, PlayUseItem, PlayUseItemSpec,
3452        test_play_use_item, bench_write_play_use_item, bench_read_play_use_item);
3453
3454    // trust me, this is some cutting edge shit
3455    // I'm definitely not generating code using a unit test
3456    #[test]
3457    fn test_generate_test_cases() {
3458        Packet578::describe().packets.iter().map(move |packet| {
3459            let snake_case = to_snake_case(packet.name.clone());
3460            alloc::format!("packet_test_cases!(RawPacket578, Packet578, {}, {},\n        test_{}, bench_write_{}, bench_read_{});\n",
3461                    packet.name, packet.body_struct, snake_case, snake_case, snake_case).to_owned()
3462        }).for_each(move |line| {
3463            println!("{}", line)
3464        })
3465    }
3466
3467    fn to_snake_case(camel: String) -> String {
3468        let mut parts = Vec::new();
3469        let mut buf = String::new();
3470        for c in camel.chars() {
3471            if !buf.is_empty() && char::is_uppercase(c) {
3472                parts.push(buf);
3473                buf = String::new();
3474            }
3475
3476            buf.push(c.to_ascii_lowercase());
3477        }
3478
3479        if !buf.is_empty() {
3480            parts.push(buf);
3481        }
3482
3483        parts.join("_")
3484    }
3485}