# !StartDocs: Types

BehaviourPackInfos: []li16
   uuid: string
   version: string
   size: lu64
   content_key: string
   sub_pack_name: string
   content_identity: string
   has_scripts: bool

TexturePackInfos: []li16
   uuid: string
   version: string
   size: lu64
   content_key: string
   sub_pack_name: string
   content_identity: string
   has_scripts: bool
   rtx_enabled: bool

ResourcePackIdVersions: []varint
   # The ID of the resource pack.
   uuid: string
   # The version of the resource pack.
   version: string
   # The subpack name of the resource pack.
   name: string

ResourcePackIds: string[]li16

Experiment:
   name: string
   enabled: bool

Experiments: Experiment[]li32

GameMode: zigzag32 =>
   0: survival
   1: creative
   2: adventure
   3: survival_spectator
   4: creative_spectator
   5: fallback  

GameRule:
   name: string
   type: varint =>
      1: bool
      2: int
      3: float
   value: type?
      if bool: bool
      if int: zigzag32
      if float: lf32

GameRules: GameRule[]varint

# CacheBlob represents a blob as used in the client side blob cache protocol. It holds a hash of its data and
# the full data of it.
Blob:
   # Hash is the hash of the blob. The hash is computed using xxHash, and must be deterministic for the same
   # chunk data.
   hash: lu64
   # Payload is the data of the blob. When sent, the client will associate the Hash of the blob with the
   # Payload in it.
   payload: ByteArray

BlockPalette: []varint
   name: string
   state: nbt

Itemstates: []varint
   name: string
   runtime_id: li16
   component_based: bool

Item:
   network_id: zigzag32
   _: network_id?
      if 0: void
      default:
         auxiliary_value: zigzag32
         has_nbt: lu16 =>
            0xffff: 'true'
            0x0000: 'false'
         nbt: has_nbt?
            if true:
               version: u8
               nbt: nbt
            default: void
         can_place_on: string[]zigzag32
         can_destroy: string[]zigzag32
   _: network_id?
      if 355:
         blocking_tick: zigzag64

vec3i:
   x: zigzag32
   y: zigzag32
   z: zigzag32

vec3u:
   x: varint
   y: varint
   z: varint

vec3f:
   x: lf32
   y: lf32
   z: lf32

vec2f:
   x: lf32
   z: lf32

MetadataDictionary: []varint
   # https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/entity/Entity.php#L101
   key: varint =>
      0: index
      1: health #int (minecart/boat)
      2: variant #int
      3: color #byte
      4: nametag #string
      5: owner_eid #long
      6: target_eid #long
      7: air #short
      8: potion_color #int (ARGB!)
      9: potion_ambient #byte
      10: jump_duration #long
      11: hurt_time #int (minecart/boat)
      12: hurt_direction #int (minecart/boat)
      13: paddle_time_left #float
      14: paddle_time_right #float
      15: experience_value #int (xp orb)
      16: minecart_display_block #int (id | (data << 16))
      17: minecart_display_offset #int
      18: minecart_has_display #byte (must be 1 for minecart to show block inside)
      20: old_swell
      21: swell_dir
      22: charge_amount
      23: enderman_held_runtime_id #short
      24: entity_age #short
      26: player_flags
      27: player_index
      28: player_bed_position #block coords
      29: fireball_power_x #float
      30: fireball_power_y
      31: fireball_power_z
      32: aux_power
      33: fish_x
      34: fish_z
      35: fish_angle
      36: potion_aux_value #short
      37: lead_holder_eid #long
      38: scale
      39: interactive_tag #string
      40: npc_skin_id #string
      41: url_tag #string
      42: max_airdata_max_air
      43: mark_variant #int
      44: container_type #byte
      45: container_base_size #int
      46: container_extra_slots_per_strength #int
      47: block_target
      48: wither_invulnerable_ticks #int
      49: wither_target_1 #long
      50: wither_target_2 #long
      51: wither_target_3 #long
      52: aerial_attack
      53: boundingbox_width
      54: boundingbox_height
      55: fuse_length
      56: rider_seat_position #vector3f
      57: rider_rotation_locked #byte
      58: rider_max_rotation #float
      59: rider_min_rotation #float
      60: area_effect_cloud_radius #float
      61: area_effect_cloud_waiting #int
      62: area_effect_cloud_particle_id #int
      63: shulker_peek_id #int
      64: shulker_attach_face #byte
      65: shulker_attached #short
      66: shulker_attach_pos
      67: trading_player_eid #long
      68: trading_career
      69: has_command_block
      70: command_block_command #string
      71: command_block_last_output #string
      72: command_block_track_output #byte
      73: controlling_rider_seat_number #byte
      74: strength #int
      75: max_strength #int
      76: spell_casting_color #int
      77: limited_life
      78: armor_stand_pose_index # int
      79: ender_crystal_time_offset # int
      80: always_show_nametag # byte
      81: color_2 # byte
      82: name_author
      83: score_tag #String
      84: balloon_attached_entity # long
      85: pufferfish_size
      86: bubble_time
      87: agent
      88: sitting_amount
      89: sitting_amount_previous
      90: eating_counter
      91: flags_extended
      92: laying_amount
      93: laying_amount_previous
      94: duration
      95: spawn_time
      96: change_rate
      97: change_on_pickup
      98: pickup_count
      99: interact_text
      100: trade_tier
      101: max_trade_tier
      102: trade_experience
      103: skin_id
      104: spawning_frames
      105: command_block_tick_delay
      106: command_block_execute_on_first_tick
      107: ambient_sound_interval
      108: ambient_sound_interval_range
      109: ambient_sound_event_name
      110: fall_damage_multiplier
      111: name_raw_text
      112: can_ride_target
      113: low_tier_cured_discount
      114: high_tier_cured_discount
      115: nearby_cured_discount
      116: nearby_cured_discount_timestamp
      117: hitbox
      118: is_buoyant
      119: buoyancy_data
   type: varint =>
      0: byte
      1: short
      2: int
      3: float
      4: string
      5: compound
      6: vec3i
      7: long
      8: vec3f
   value: type?
      if byte: i8
      if short: li16
      if int: zigzag32
      if float: lf32
      if string: string
      if compound: nbt
      if vec3i: vec3i
      if long: zigzag64
      if vec3f: vec3f

Link:
   ridden_entity_id: zigzag64
   rider_entity_id: zigzag64
   type: u8
   immediate: bool
   rider_initiated: bool

Links: Link[]varint

EntityAttributes: []varint
   name: string
   min: lf32
   value: lf32
   max: lf32

Rotation:
   yaw: byterot
   pitch: byterot
   head_yaw: byterot

BlockCoordinates: # mojang...
   x: zigzag32
   y: varint
   z: zigzag32

PlayerAttributes: []varint
   min: lf32
   max: lf32
   current: lf32
   default: lf32
   name: string

Transaction:
   # LegacyRequestID is an ID that is only non-zero at times when sent by the client. The server should
   # always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values
   # in it.
   # LegacyRequestID ties in with the ItemStackResponse packet. If this field is non-0, the server should
   # respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the
   # hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it.
   legacy_request_id: zigzag32
   # `legacy_transactions` are only present if the LegacyRequestID is non-zero. These item slots inform the
   # server of the slots that were changed during the inventory transaction, and the server should send
   # back an ItemStackResponse packet with these slots present in it. (Or false with no slots, if rejected.)
   legacy_transactions: legacy_request_id?
      if 0: void
      default: []varint
         container_id: u8
         changed_slots: []varint
            slot_id: u8
   transaction_type: varint =>
      0: normal
      1: inventory_mismatch
      2: item_use
      3: item_use_on_entity
      4: item_release
   network_ids: bool
   inventory_actions: []varint
      source_type: varint =>
         0: container
         1: global
         2: world_interaction
         3: creative
         100: craft_slot
         99999: craft
      _: source_type?
         if container or creative:
            inventory_id: varint
         if world_interaction:
            flags: varint
         if craft or craft_slot:
            action: varint
         default: void
      slot: varint
      old_item: Item
      new_item: Item
      new_item_stack_id: ../network_ids?
         if true:  zigzag32
         default: void
   transaction_data: transaction_type?
      if normal or inventory_mismatch: void
      # UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on
      # a block.
      if item_use:
         # ActionType is the type of the UseItem inventory transaction. It is one of the action types found above,
         # and specifies the way the player interacted with the block.
         action_type: varint =>
            0: click_block
            1: click_air
            2: break_block
         # BlockPosition is the position of the block that was interacted with. This is only really a correct
         # block position if ActionType is not UseItemActionClickAir.
         block_position: BlockCoordinates
         # BlockFace is the face of the block that was interacted with. When clicking the block, it is the face
         # clicked. When breaking the block, it is the face that was last being hit until the block broke.
         face: varint
         # HotBarSlot is the hot bar slot that the player was holding while clicking the block. It should be used
         # to ensure that the hot bar slot and held item are correctly synchronised with the server.
         hotbar_slot: varint
         # HeldItem is the item that was held to interact with the block. The server should check if this item
         # is actually present in the HotBarSlot.
         held_item: Item
         # Position is the position of the player at the time of interaction. For clicking a block, this is the
         # position at that time, whereas for breaking the block it is the position at the time of breaking.
         player_pos: vec3f
         # ClickedPosition is the position that was clicked relative to the block's base coordinate. It can be
         # used to find out exactly where a player clicked the block.
         click_pos: vec3f
         # BlockRuntimeID is the runtime ID of the block that was clicked. It may be used by the server to verify
         # that the player's world client-side is synchronised with the server's.
         block_runtime_id: varint
      # UseItemOnEntityTransactionData represents an inventory transaction data object sent when the client uses
      # an item on an entity.
      if item_use_on_entity:
         # TargetEntityRuntimeID is the entity runtime ID of the target that was clicked. It is the runtime ID
         # that was assigned to it in the AddEntity packet.
         entity_runtime_id: varint64
         # ActionType is the type of the UseItemOnEntity inventory transaction. It is one of the action types
         # found in the constants above, and specifies the way the player interacted with the entity.
         action_type: varint =>
            0: interact
            1: attack
         # HotBarSlot is the hot bar slot that the player was holding while clicking the entity. It should be used
         # to ensure that the hot bar slot and held item are correctly synchronised with the server.
         hotbar_slot: zigzag32
         # HeldItem is the item that was held to interact with the entity. The server should check if this item
         # is actually present in the HotBarSlot.
         held_item: Item
         # Position is the position of the player at the time of clicking the entity.
         player_pos: vec3f
         # ClickedPosition is the position that was clicked relative to the entity's base coordinate. It can be
         # used to find out exactly where a player clicked the entity.
         click_pos: vec3f
      # ReleaseItemTransactionData represents an inventory transaction data object sent when the client releases
      # the item it was using, for example when stopping while eating or stopping the charging of a bow.        
      if item_release:
         # ActionType is the type of the ReleaseItem inventory transaction. It is one of the action types found
         # in the constants above, and specifies the way the item was released.
         # As of 1.13, the ActionType is always 0. This field can be ignored, because releasing food (by consuming
         # it) or releasing a bow (to shoot an arrow) is essentially the same.
         action_type: varint =>
            0: release
            1: consume
         # HotBarSlot is the hot bar slot that the player was holding while releasing the item. It should be used
         # to ensure that the hot bar slot and held item are correctly synchronised with the server.
         hotbar_slot: zigzag32
         # HeldItem is the item that was released. The server should check if this item is actually present in the
         # HotBarSlot.
         held_item: Item
         # HeadPosition is the position of the player's head at the time of releasing the item. This is used
         # mainly for purposes such as spawning eating particles at that position.
         head_pos: vec3f

# An "ItemStack" here represents an Item instance. You can think about it like a pointer
# to an item class. The data for the class gets updated with the data in the `item` field
ItemStack:
   # StackNetworkID is the network ID of the item stack. If the stack is empty, 0 is always written for this
   # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the
   # StartGame packet, or to a unique stack ID if it is enabled.
   runtime_id: zigzag32
   # Stack is the actual item stack of the item instance.
   item: Item

ItemStacks: ItemStack[]varint

RecipeIngredient:
   network_id: zigzag32
   _: network_id?
      if 0: void
      default:
         network_data: zigzag32
         count: zigzag32

PotionTypeRecipes: []varint
   input_item_id: zigzag32
   input_item_meta: zigzag32
   ingredient_id: zigzag32
   ingredient_meta: zigzag32
   output_item_id: zigzag32
   output_item_meta: zigzag32

PotionContainerChangeRecipes: []varint
   input_item_id: zigzag32
   ingredient_id: zigzag32
   output_item_id: zigzag32

Recipes: []varint
   type: zigzag32 =>
      '0': 'shapeless' #'ENTRY_SHAPELESS',
      '1': 'shaped' #'ENTRY_SHAPED',
      '2': 'furnace' # 'ENTRY_FURNACE',
      # `furnace_with_metadata` is a recipe specifically used for furnace-type crafting stations. It is equal to
      # `furnace`, except it has an input item with a specific metadata value, instead of any metadata value.
      '3': 'furnace_with_metadata' # 'ENTRY_FURNACE_DATA', // has metadata
      '4': 'multi' #'ENTRY_MULTI', //TODO
      '5': 'shulker_box' #'ENTRY_SHULKER_BOX', //TODO
      '6': 'shapeless_chemistry' #'ENTRY_SHAPELESS_CHEMISTRY', //TODO
      '7': 'shaped_chemistry' #'ENTRY_SHAPED_CHEMISTRY', //TODO
   recipe: type?
      if shapeless or shulker_box or shapeless_chemistry:
         recipe_id: string
         input: RecipeIngredient[]varint
         output: Item[]varint
         uuid: uuid
         block: string
         priority: zigzag32
         network_id: zigzag32
      if shaped or shaped_chemistry:
         recipe_id: string
         width: zigzag32
         height: zigzag32
         # todo: can this become
         # RecipeIngredient[$height][$width] or RecipeIngredient[]$height[]$width ?
         input: []$width
            _: RecipeIngredient[]$height
         output: Item[]varint
         uuid: uuid
         block: string
         priority: zigzag32
         network_id: zigzag32
      if furnace:
         input_id: zigzag32
         output: Item
         block: string
      if furnace_with_metadata:
         input_id: zigzag32
         input_meta: zigzag32
         output: Item
         block: string
      if multi:
         uuid: uuid
         network_id: zigzag32

SkinImage:
   width: li32
   height: li32
   data: string

Skin:
   skin_id: string
   skin_resource_pack: string
   skin_data: SkinImage
   animations: []li32
      skin_image: SkinImage
      animation_type: li32
      animation_frames: lf32
      expression_type: lf32
   cape_data: SkinImage
   geometry_data: string
   animation_data: string
   premium: string
   persona: bool
   cape_on_classic: bool
   cape_id: string
   full_skin_id: string
   arm_size: string
   skin_color: string
   personal_pieces: []li32
      piece_id: string
      piece_type: string
      pack_id: string
      is_default_piece: bool
      product_id: string
   piece_tint_colors: []li32
      piece_type: string
      colors: string[]li32

PlayerRecords:
   type: u8 =>
      0: add
      1: remove
   records_count: varint
   records: []$records_count
      _: type?
         if add:
            uuid: uuid
            entity_unique_id: zigzag64
            username: string
            xbox_user_id: string
            platform_chat_id: string
            build_platform: li32
            skin_data: Skin
            is_teacher: bool
            is_host: bool
         if remove:
            uuid: uuid
   verified: bool[]$records_count

ScoreEntries:
   type: u8 =>
      0: change
      1: remove
   entries: []varint
      scoreboard_id: zigzag64
      objective_name: string
      score: li32
      _: type?
         if remove:
            entry_type: i8 =>
               1: player
               2: entity
               3: fake_player
            entity_unique_id: entry_type?
               if player or entity: zigzag64
            custom_name: entry_type?
               if fake_player: string

ScoreboardIdentityEntries:
   type: i8 =>
      0: TYPE_REGISTER_IDENTITY
      1: TYPE_CLEAR_IDENTITY
   entries: []varint
      scoreboard_id: zigzag64
      entity_unique_id: type ?
         if TYPE_REGISTER_IDENTITY: zigzag64
         default: void

Enchant:
   id: u8
   level: u8

EnchantOptions: []varint
   cost: varint
   slot_flags: li32
   equip_enchants: Enchant[]varint
   held_enchants: Enchant[]varint
   self_enchants: Enchant[]varint
   name: string
   option_id: zigzag32


StackRequestSlotInfo:
   container_id: u8
   slot_id: u8
   stack_id: zigzag32

#

ItemStackRequests: []varint
   # RequestID is a unique ID for the request. This ID is used by the server to send a response for this
   # specific request in the ItemStackResponse packet.
   request_id: zigzag32
   actions: []varint
      type_id: u8 =>
         # TakeStackRequestAction is sent by the client to the server to take x amount of items from one slot in a
         # container to the cursor.
         0: take
         # PlaceStackRequestAction is sent by the client to the server to place x amount of items from one slot into
         # another slot, such as when shift clicking an item in the inventory to move it around or when moving an item
         # in the cursor into a slot.
         1: place
         # SwapStackRequestAction is sent by the client to swap the item in its cursor with an item present in another
         # container. The two item stacks swap places. 
         2: swap
         # DropStackRequestAction is sent by the client when it drops an item out of the inventory when it has its
         # inventory opened. This action is not sent when a player drops an item out of the hotbar using the Q button
         # (or the equivalent on mobile). The InventoryTransaction packet is still used for that action, regardless of
         # whether the item stack network IDs are used or not.
         3: drop
         # DestroyStackRequestAction is sent by the client when it destroys an item in creative mode by moving it
         # back into the creative inventory.
         4: destroy
         # ConsumeStackRequestAction is sent by the client when it uses an item to craft another item. The original
         # item is 'consumed'.
         5: consume
         # CreateStackRequestAction is sent by the client when an item is created through being used as part of a
         # recipe. For example, when milk is used to craft a cake, the buckets are leftover. The buckets are moved to
         # the slot sent by the client here.
         # Note that before this is sent, an action for consuming all items in the crafting table/grid is sent. Items
         # that are not fully consumed when used for a recipe should not be destroyed there, but instead, should be
         # turned into their respective resulting items. 
         6: create 
         # LabTableCombineStackRequestAction is sent by the client when it uses a lab table to combine item stacks.
         7: lab_table_combine
         # BeaconPaymentStackRequestAction is sent by the client when it submits an item to enable effects from a
         # beacon. These items will have been moved into the beacon item slot in advance. 
         8: beacon_payment
         # CraftRecipeStackRequestAction is sent by the client the moment it begins crafting an item. This is the
         # first action sent, before the Consume and Create item stack request actions.
         # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as
         # crafting, where the old item is consumed.
         9: craft_recipe
         # AutoCraftRecipeStackRequestAction is sent by the client similarly to the CraftRecipeStackRequestAction. The
         # only difference is that the recipe is automatically created and crafted by shift clicking the recipe book.
         10: craft_recipe_auto  #recipe book?
         # CraftCreativeStackRequestAction is sent by the client when it takes an item out fo the creative inventory.
         # The item is thus not really crafted, but instantly created.
         11: craft_creative
         # CraftRecipeOptionalStackRequestAction is sent when using an anvil. When this action is sent, the
         # CustomNames field in the respective stack request is non-empty and contains the name of the item created
         # using the anvil.
         12: optional
         # CraftNonImplementedStackRequestAction is an action sent for inventory actions that aren't yet implemented
         # in the new system. These include, for example, anvils.
         13: non_implemented  #anvils aren't fully implemented yet
         # CraftResultsDeprecatedStackRequestAction is an additional, deprecated packet sent by the client after
         # crafting. It holds the final results and the amount of times the recipe was crafted. It shouldn't be used.
         # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as
         # crafting, where the old item is consumed.
         14: results_deprecated
      _: type_id ?
         if take or place:
            count: u8
            source: StackRequestSlotInfo
            destination: StackRequestSlotInfo
         if swap:
            # Source and Destination point to the source slot from which Count of the item stack were taken and the
            # destination slot to which this item was moved.
            source: StackRequestSlotInfo
            destination: StackRequestSlotInfo
         if drop:
            # Count is the count of the item in the source slot that was taken towards the destination slot.
            count: u8
            # Source is the source slot from which items were dropped to the ground.
            source: StackRequestSlotInfo
            # Randomly seems to be set to false in most cases. I'm not entirely sure what this does, but this is what
            # vanilla calls this field.
            randomly: bool
         if destroy or consume:
            # Count is the count of the item in the source slot that was destroyed.
            count: u8
            # Source is the source slot from which items came that were destroyed by moving them into the creative
            # inventory.
            source: StackRequestSlotInfo
         if create:
            # ResultsSlot is the slot in the inventory in which the results of the crafting ingredients are to be
            # placed.
            result_slot_id: u8
         if beacon_payment:
            # PrimaryEffect and SecondaryEffect are the effects that were selected from the beacon.
            primary_effect: zigzag32
            secondary_effect: zigzag32
         if craft_recipe or craft_recipe_auto:
            # RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches
            # one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as
            # of 1.16.
            recipe_network_id: varint
         if craft_creative:
            # CreativeItemNetworkID is the network ID of the creative item that is being created. This is one of the
            # creative item network IDs sent in the CreativeContent packet.
            creative_item_network_id: varint32
         if optional:
            # For the cartography table, if a certain MULTI recipe is being called, this points to the network ID that was assigned.
            recipe_network_id: varint
            # Most likely the index in the request's filter strings that this action is using
            filtered_string_index: li32
         if non_implemented: void
         if results_deprecated:
            result_items: Item[]varint
            times_crafted: u8
   # CustomNames is a list of custom names involved in the request. This is typically filled with one string
   # when an anvil is used.
   # * Used for the server to determine which strings should be filtered. Used in anvils to verify a renamed item.
   custom_names: string[]varint

ItemStackResponses: []varint
   result: u8
   request_id: varint32
   containers: []varint
      container_id: u8
      slots: []varint
         slot: u8
         hotbar_slot: u8
         count: u8
         item_stack_id: varint32
         custom_name: string

ItemComponentList: []varint
   # Name is the name of the item, which is a name like 'minecraft:stick'.
   name: string
   # Data is a map containing the components and properties of the item.
   nbt: nbt

CommandOrigin:
   # Origin is one of the values above that specifies the origin of the command. The origin may change,
   # depending on what part of the client actually called the command. The command may be issued by a
   # websocket server, for example.
   type: varint =>
      0: player
      1: block
      2: minecart_block
      3: dev_console
      4: test
      5: automation_player
      6: client_automation
      7: dedicated_server
      8: entity
      9: virtual
      10: game_argument
      11: entity_server
   # UUID is the UUID of the command called. This UUID is a bit odd as it is not specified by the server. It
   # is not clear what exactly this UUID is meant to identify, but it is unique for each command called.
   uuid: uuid
   # RequestID is an ID that identifies the request of the client. The server should send a CommandOrigin
   # with the same request ID to ensure it can be matched with the request by the caller of the command.
   # This is especially important for websocket servers and it seems that this field is only non-empty for
   # these websocket servers.
   request_id: string
   # PlayerUniqueID is an ID that identifies the player, the same as the one found in the AdventureSettings
   # packet. Filling it out with 0 seems to work.
   # PlayerUniqueID is only written if Origin is CommandOriginDevConsole or CommandOriginTest.
   player_entity_id: type?
      if dev_console or test:
         player_entity_id: zigzag64

# Some arbitrary definitions from CBMC, Window IDs are normally
# unique + sequential
WindowID: i8 =>
   -100: drop_contents
   -24: beacon
   -23: trading_output
   -22: trading_use_inputs
   -21: trading_input_2
   -20: trading_input_1
   -17: enchant_output
   -16: enchant_material
   -15: enchant_input
   -13: anvil_output
   -12: anvil_result
   -11: anvil_material
   -10: container_input
   -5: crafting_use_ingredient
   -4: crafting_result
   -3: crafting_remove_ingredient
   -2: crafting_add_ingredient
   -1: none
   0: inventory
   1: first
   100: last
   119: offhand
   120: armor
   121: creative
   122: hotbar
   123: fixed_inventory
   124: ui

WindowType: u8 =>
   0: container
   1: workbench
   2: furnace
   3: enchantment
   4: brewing_stand
   5: anvil
   6: dispenser
   7: dropper
   8: hopper
   9: cauldron
   10: minecart_chest
   11: minecart_hopper
   12: horse
   13: beacon
   14: structure_editor
   15: trading
   16: command_block
   17: jukebox
   18: armor
   19: hand
   20: compound_creator
   21: element_constructor
   22: material_reducer
   23: lab_table
   24: loom
   25: lectern
   26: grindstone
   27: blast_furnace
   28: smoker
   29: stonecutter
   30: cartography
   31: hud
   32: jigsaw_editor
   33: smithing_table

# TODO: remove?
LegacyEntityType: li32 =>
   10: chicken
   11: cow
   12: pig
   13: sheep
   14: wolf
   15: villager
   16: mooshroom
   17: squid
   18: rabbit
   19: bat
   20: iron_golem
   21: snow_golem
   22: ocelot
   23: horse
   24: donkey
   25: mule
   26: skeleton_horse
   27: zombie_horse
   28: polar_bear
   29: llama
   30: parrot
   31: dolphin
   32: zombie
   33: creeper
   34: skeleton
   35: spider
   36: zombie_pigman
   37: slime
   38: enderman
   39: silverfish
   40: cave_spider
   41: ghast
   42: magma_cube
   43: blaze
   44: zombie_villager
   45: witch
   46: stray
   47: husk
   48: wither_skeleton
   49: guardian
   50: elder_guardian
   51: npc
   52: wither
   53: ender_dragon
   54: shulker
   55: endermite
   56: agent # LEARN_TO_CODE_MASCOT
   57: vindicator
   58: phantom
   61: armor_stand
   62: tripod_camera
   63: player
   64: item
   65: tnt
   66: falling_block
   67: moving_block
   68: xp_bottle
   69: xp_orb
   70: eye_of_ender_signal
   71: ender_crystal
   72: fireworks_rocket
   73: thrown_trident
   74: turtle
   75: cat
   76: shulker_bullet
   77: fishing_hook
   78: chalkboard
   79: dragon_fireball
   80: arrow
   81: snowball
   82: egg
   83: painting
   84: minecart
   85: fireball
   86: splash_potion
   87: ender_pearl
   88: leash_knot
   89: wither_skull
   90: boat
   91: wither_skull_dangerous
   93: lightning_bolt
   94: small_fireball
   95: area_effect_cloud
   96: hopper_minecart
   97: tnt_minecart
   98: chest_minecart
   100: command_block_minecart
   101: lingering_potion
   102: llama_spit
   103: evocation_fang
   104: evocation_illager
   105: vex
   106: ice_bomb
   107: balloon
   108: pufferfish
   109: salmon
   110: drowned
   111: tropicalfish
   112: cod
   113: panda