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