1.16.220 support (#66)
* 1.16.220 initial support * 1.16.220 fixes, electron gcm * 1.16.220 item stack fix
This commit is contained in:
parent
d8ff48258c
commit
d3723ef42a
16 changed files with 8920 additions and 133 deletions
8315
data/1.16.220/protocol.json
Normal file
8315
data/1.16.220/protocol.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,13 +1,14 @@
|
|||
# Created from MiNET and gophertunnel docs
|
||||
# The version below is the latest version this protocol schema was updated for.
|
||||
# The output protocol.json will be in the folder for the version
|
||||
!version: 1.16.210
|
||||
!version: 1.16.220
|
||||
|
||||
# Some ProtoDef aliases
|
||||
string: ["pstring",{"countType":"varint"}]
|
||||
ByteArray: ["buffer",{"countType":"varint"}]
|
||||
SignedByteArray: ["buffer",{"countType":"zigzag32"}]
|
||||
LittleString: ["pstring",{"countType":"li32"}]
|
||||
ShortArray: ["buffer",{"countType":"li16"}]
|
||||
varint32: varint
|
||||
bool: native
|
||||
zigzag32: native
|
||||
|
|
@ -622,17 +623,45 @@ packet_level_event:
|
|||
1060: sound_armor_stand_break
|
||||
1061: sound_armor_stand_hit
|
||||
1062: sound_armor_stand_fall
|
||||
1063: sound_armor_stand_place
|
||||
1063: sound_armor_stand_place
|
||||
1064: pointed_dripstone_land
|
||||
1065: dye_used
|
||||
1066: ink_sack_used
|
||||
2000: particle_shoot #TODO: check 2000-2017
|
||||
2001: particle_destroy
|
||||
2002: particle_splash
|
||||
2003: particle_eye_despawn
|
||||
2004: particle_spawn
|
||||
2006: guardian_curse
|
||||
2005: particle_crop_growth
|
||||
2006: particle_guardian_curse
|
||||
2007: particle_death_smoke
|
||||
2008: particle_block_force_field
|
||||
2009: particle_projectile_hit
|
||||
2009: particle_projectile_hit
|
||||
2010: particle_dragon_egg_teleport
|
||||
2011: particle_crop_eaten
|
||||
2012: particle_critical
|
||||
2013: particle_enderman_teleport
|
||||
2014: particle_punch_block
|
||||
2014: particle_punch_block
|
||||
2015: particle_bubble
|
||||
2016: particle_evaporate
|
||||
2017: particle_destroy_armor_stand
|
||||
2018: particle_breaking_egg
|
||||
2019: particle_destroy_egg
|
||||
2020: particle_evaporate_water
|
||||
2021: particle_destroy_block_no_sound
|
||||
2022: particle_knockback_roar
|
||||
2023: particle_teleport_trail
|
||||
2024: particle_point_cloud
|
||||
2025: particle_explosion
|
||||
2026: particle_block_explosion
|
||||
2027: particle_vibration_signal
|
||||
2028: particle_dripstone_drip
|
||||
2029: particle_fizz_effect
|
||||
2030: particle_wax_on
|
||||
2031: particle_wax_off
|
||||
2032: particle_scrape
|
||||
2033: particle_electric_spark
|
||||
|
||||
3001: start_rain
|
||||
3002: start_thunder
|
||||
3003: stop_rain
|
||||
|
|
@ -966,7 +995,7 @@ packet_inventory_slot:
|
|||
slot: varint
|
||||
# NewItem is the item to be put in the slot at Slot. It will overwrite any item that may currently
|
||||
# be present in that slot.
|
||||
item: ItemStack
|
||||
item: Item
|
||||
|
||||
# ContainerSetData is sent by the server to update specific data of a single container, meaning a block such
|
||||
# as a furnace or a brewing stand. This data is usually used by the client to display certain features
|
||||
|
|
@ -1385,6 +1414,8 @@ packet_available_commands:
|
|||
constraints: []varint
|
||||
constraint: u8 =>
|
||||
0: cheats_enabled
|
||||
1: operator_permissions
|
||||
2: host_permissions
|
||||
|
||||
# ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not,
|
||||
# setting this to true has no effect) should be collapsed. This means that the options of the enum are
|
||||
|
|
@ -1878,10 +1909,14 @@ packet_biome_definition_list:
|
|||
!bound: client
|
||||
nbt: nbt
|
||||
|
||||
# LevelSoundEvent is sent by the server to make any kind of built-in sound heard to a player. It is sent to,
|
||||
# for example, play a stepping sound or a shear sound. The packet is also sent by the client, in which case
|
||||
# it could be forwarded by the server to the other players online. If possible, the packets from the client
|
||||
# should be ignored however, and the server should play them on its own accord.
|
||||
packet_level_sound_event:
|
||||
!id: 0x7b
|
||||
!bound: both
|
||||
sound_id: varint
|
||||
sound_id: SoundType
|
||||
position: vec3f
|
||||
block_id: zigzag32
|
||||
entity_type: string
|
||||
|
|
@ -2210,7 +2245,9 @@ InputFlag: [ "bitflags", {
|
|||
packet_creative_content:
|
||||
!id: 0x91
|
||||
!bound: client
|
||||
items: ItemStacks
|
||||
items: []varint
|
||||
entry_id: varint
|
||||
item: ItemLegacy
|
||||
|
||||
packet_player_enchant_options:
|
||||
!id: 0x92
|
||||
|
|
|
|||
|
|
@ -75,25 +75,72 @@ Itemstates: []varint
|
|||
runtime_id: li16
|
||||
component_based: bool
|
||||
|
||||
# Start of item crap ...
|
||||
|
||||
ItemExtraDataWithBlockingTick:
|
||||
has_nbt: lu16 =>
|
||||
0xffff: 'true'
|
||||
0x0000: 'false'
|
||||
nbt: has_nbt ?
|
||||
if true:
|
||||
version: u8
|
||||
nbt: lnbt
|
||||
default: void
|
||||
can_place_on: ShortArray[]li32
|
||||
can_destroy: ShortArray[]li32
|
||||
blocking_tick: li64
|
||||
|
||||
ItemExtraDataWithoutBlockingTick:
|
||||
has_nbt: lu16 =>
|
||||
0xffff: 'true'
|
||||
0x0000: 'false'
|
||||
nbt: has_nbt ?
|
||||
if true:
|
||||
version: u8
|
||||
nbt: lnbt
|
||||
default: void
|
||||
can_place_on: ShortArray[]li32
|
||||
can_destroy: ShortArray[]li32
|
||||
|
||||
# Same as below but without a "networkStackID" boolean ...
|
||||
ItemLegacy:
|
||||
network_id: zigzag32
|
||||
_: network_id?
|
||||
if 0: void
|
||||
default:
|
||||
count: lu16
|
||||
metadata: varint
|
||||
block_runtime_id: zigzag32
|
||||
extra: network_id ?
|
||||
if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]'
|
||||
default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]'
|
||||
|
||||
# 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
|
||||
# As of 1.16.220, now functionally the same as `Item` just without an extra boolean when
|
||||
# server auth inventories is disabled.
|
||||
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
|
||||
count: lu16
|
||||
metadata: varint
|
||||
# When server authoritative inventory is enabled, all allocated items have a unique ID used to identify
|
||||
# a specifc item instance.
|
||||
has_stack_id: u8
|
||||
# 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.
|
||||
stack_id: has_stack_id ?
|
||||
if 0: void
|
||||
default: zigzag32
|
||||
block_runtime_id: zigzag32
|
||||
extra: network_id ?
|
||||
if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]'
|
||||
default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]'
|
||||
|
||||
# end of item crap
|
||||
|
||||
vec3i:
|
||||
x: zigzag32
|
||||
|
|
@ -413,7 +460,7 @@ TransactionUseItem:
|
|||
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
|
||||
block_position: vec3i
|
||||
# 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
|
||||
|
|
@ -438,7 +485,6 @@ TransactionUseItem:
|
|||
# all of these actions results in a balanced inventory transaction. This should be checked to ensure that
|
||||
# no items are cheated into the inventory.
|
||||
TransactionActions:
|
||||
network_ids: bool
|
||||
actions: []varint
|
||||
source_type: varint =>
|
||||
0: container
|
||||
|
|
@ -458,9 +504,6 @@ TransactionActions:
|
|||
slot: varint
|
||||
old_item: Item
|
||||
new_item: Item
|
||||
new_item_stack_id: ../network_ids?
|
||||
if true: zigzag32
|
||||
default: void
|
||||
|
||||
# The Minecraft bedrock inventory system was refactored, but not all inventory actions use the new packet.
|
||||
# This data structure holds actions that have not been updated to the new system.
|
||||
|
|
@ -542,17 +585,7 @@ Transaction:
|
|||
# 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.
|
||||
stack_id: varint
|
||||
# Stack is the actual item stack of the item instance.
|
||||
item: Item
|
||||
|
||||
ItemStacks: ItemStack[]varint
|
||||
ItemStacks: Item[]varint
|
||||
|
||||
RecipeIngredient:
|
||||
network_id: zigzag32
|
||||
|
|
@ -591,7 +624,7 @@ Recipes: []varint
|
|||
if shapeless or shulker_box or shapeless_chemistry:
|
||||
recipe_id: string
|
||||
input: RecipeIngredient[]varint
|
||||
output: Item[]varint
|
||||
output: ItemLegacy[]varint
|
||||
uuid: uuid
|
||||
block: string
|
||||
priority: zigzag32
|
||||
|
|
@ -604,19 +637,19 @@ Recipes: []varint
|
|||
# RecipeIngredient[$height][$width] or RecipeIngredient[]$height[]$width ?
|
||||
input: []$width
|
||||
_: RecipeIngredient[]$height
|
||||
output: Item[]varint
|
||||
output: ItemLegacy[]varint
|
||||
uuid: uuid
|
||||
block: string
|
||||
priority: zigzag32
|
||||
network_id: varint
|
||||
if furnace:
|
||||
input_id: zigzag32
|
||||
output: Item
|
||||
output: ItemLegacy
|
||||
block: string
|
||||
if furnace_with_metadata:
|
||||
input_id: zigzag32
|
||||
input_meta: zigzag32
|
||||
output: Item
|
||||
output: ItemLegacy
|
||||
block: string
|
||||
if multi:
|
||||
uuid: uuid
|
||||
|
|
@ -889,7 +922,7 @@ ItemStackRequest:
|
|||
filtered_string_index: li32
|
||||
if non_implemented: void
|
||||
if results_deprecated:
|
||||
result_items: Item[]varint
|
||||
result_items: ItemLegacy[]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.
|
||||
|
|
@ -959,6 +992,10 @@ CommandOrigin:
|
|||
9: virtual
|
||||
10: game_argument
|
||||
11: entity_server
|
||||
12: precompiled
|
||||
13: game_director_entity_server # ?
|
||||
14: script
|
||||
|
||||
# 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
|
||||
|
|
@ -1135,6 +1172,344 @@ ContainerSlotType: u8 =>
|
|||
- cursor
|
||||
- creative_output
|
||||
|
||||
SoundType: varint =>
|
||||
- ItemUseOn
|
||||
- Hit
|
||||
- Step
|
||||
- Fly
|
||||
- Jump
|
||||
- Break
|
||||
- Place
|
||||
- HeavyStep
|
||||
- Gallop
|
||||
- Fall
|
||||
- Ambient
|
||||
- AmbientBaby
|
||||
- AmbientInWater
|
||||
- Breathe
|
||||
- Death
|
||||
- DeathInWater
|
||||
- DeathToZombie
|
||||
- Hurt
|
||||
- HurtInWater
|
||||
- Mad
|
||||
- Boost
|
||||
- Bow
|
||||
- SquishBig
|
||||
- SquishSmall
|
||||
- FallBig
|
||||
- FallSmall
|
||||
- Splash
|
||||
- Fizz
|
||||
- Flap
|
||||
- Swim
|
||||
- Drink
|
||||
- Eat
|
||||
- Takeoff
|
||||
- Shake
|
||||
- Plop
|
||||
- Land
|
||||
- Saddle
|
||||
- Armor
|
||||
- MobArmorStandPlace
|
||||
- AddChest
|
||||
- Throw
|
||||
- Attack
|
||||
- AttackNoDamage
|
||||
- AttackStrong
|
||||
- Warn
|
||||
- Shear
|
||||
- Milk
|
||||
- Thunder
|
||||
- Explode
|
||||
- Fire
|
||||
- Ignite
|
||||
- Fuse
|
||||
- Stare
|
||||
- Spawn
|
||||
- Shoot
|
||||
- BreakBlock
|
||||
- Launch
|
||||
- Blast
|
||||
- LargeBlast
|
||||
- Twinkle
|
||||
- Remedy
|
||||
- Infect
|
||||
- LevelUp
|
||||
- BowHit
|
||||
- BulletHit
|
||||
- ExtinguishFire
|
||||
- ItemFizz
|
||||
- ChestOpen
|
||||
- ChestClosed
|
||||
- ShulkerBoxOpen
|
||||
- ShulkerBoxClosed
|
||||
- EnderChestOpen
|
||||
- EnderChestClosed
|
||||
- PowerOn
|
||||
- PowerOff
|
||||
- Attach
|
||||
- Detach
|
||||
- Deny
|
||||
- Tripod
|
||||
- Pop
|
||||
- DropSlot
|
||||
- Note
|
||||
- Thorns
|
||||
- PistonIn
|
||||
- PistonOut
|
||||
- Portal
|
||||
- Water
|
||||
- LavaPop
|
||||
- Lava
|
||||
- Burp
|
||||
- BucketFillWater
|
||||
- BucketFillLava
|
||||
- BucketEmptyWater
|
||||
- BucketEmptyLava
|
||||
- ArmorEquipChain
|
||||
- ArmorEquipDiamond
|
||||
- ArmorEquipGeneric
|
||||
- ArmorEquipGold
|
||||
- ArmorEquipIron
|
||||
- ArmorEquipLeather
|
||||
- ArmorEquipElytra
|
||||
- Record13
|
||||
- RecordCat
|
||||
- RecordBlocks
|
||||
- RecordChirp
|
||||
- RecordFar
|
||||
- RecordMall
|
||||
- RecordMellohi
|
||||
- RecordStal
|
||||
- RecordStrad
|
||||
- RecordWard
|
||||
- Record11
|
||||
- RecordWait
|
||||
- unknown1
|
||||
- Flop
|
||||
- ElderGuardianCurse
|
||||
- MobWarning
|
||||
- MobWarningBaby
|
||||
- Teleport
|
||||
- ShulkerOpen
|
||||
- ShulkerClose
|
||||
- Haggle
|
||||
- HaggleYes
|
||||
- HaggleNo
|
||||
- HaggleIdle
|
||||
- ChorusGrow
|
||||
- ChorusDeath
|
||||
- Glass
|
||||
- PotionBrewed
|
||||
- CastSpell
|
||||
- PrepareAttack
|
||||
- PrepareSummon
|
||||
- PrepareWololo
|
||||
- Fang
|
||||
- Charge
|
||||
- CameraTakePicture
|
||||
- LeashKnotPlace
|
||||
- LeashKnotBreak
|
||||
- Growl
|
||||
- Whine
|
||||
- Pant
|
||||
- Purr
|
||||
- Purreow
|
||||
- DeathMinVolume
|
||||
- DeathMidVolume
|
||||
- unknown2
|
||||
- ImitateCaveSpider
|
||||
- ImitateCreeper
|
||||
- ImitateElderGuardian
|
||||
- ImitateEnderDragon
|
||||
- ImitateEnderman
|
||||
- unknown3
|
||||
- ImitateEvocationIllager
|
||||
- ImitateGhast
|
||||
- ImitateHusk
|
||||
- ImitateIllusionIllager
|
||||
- ImitateMagmaCube
|
||||
- ImitatePolarBear
|
||||
- ImitateShulker
|
||||
- ImitateSilverfish
|
||||
- ImitateSkeleton
|
||||
- ImitateSlime
|
||||
- ImitateSpider
|
||||
- ImitateStray
|
||||
- ImitateVex
|
||||
- ImitateVindicationIllager
|
||||
- ImitateWitch
|
||||
- ImitateWither
|
||||
- ImitateWitherSkeleton
|
||||
- ImitateWolf
|
||||
- ImitateZombie
|
||||
- ImitateZombiePigman
|
||||
- ImitateZombieVillager
|
||||
- BlockEndPortalFrameFill
|
||||
- BlockEndPortalSpawn
|
||||
- RandomAnvilUse
|
||||
- BottleDragonBreath
|
||||
- PortalTravel
|
||||
- ItemTridentHit
|
||||
- ItemTridentReturn
|
||||
- ItemTridentRiptide1
|
||||
- ItemTridentRiptide2
|
||||
- ItemTridentRiptide3
|
||||
- ItemTridentThrow
|
||||
- ItemTridentThunder
|
||||
- ItemTridentHitGround
|
||||
- Default
|
||||
- BlockFletchingTableUse
|
||||
- ElemConstructOpen
|
||||
- IceBombHit
|
||||
- BalloonPop
|
||||
- LtReactionIceBomb
|
||||
- LtReactionBleach
|
||||
- LtReactionEPaste
|
||||
- LtReactionEPaste2
|
||||
- LtReactionFertilizer
|
||||
- LtReactionFireball
|
||||
- LtReactionMgsalt
|
||||
- LtReactionMiscfire
|
||||
- LtReactionFire
|
||||
- LtReactionMiscexplosion
|
||||
- LtReactionMiscmystical
|
||||
- LtReactionMiscmystical2
|
||||
- LtReactionProduct
|
||||
- SparklerUse
|
||||
- GlowstickUse
|
||||
- SparklerActive
|
||||
- ConvertToDrowned
|
||||
- BucketFillFish
|
||||
- BucketEmptyFish
|
||||
- BubbleUp
|
||||
- BubbleDown
|
||||
- BubblePop
|
||||
- BubbleUpInside
|
||||
- BubbleDownInside
|
||||
- HurtBaby
|
||||
- DeathBaby
|
||||
- StepBaby
|
||||
- BabySpawn
|
||||
- Born
|
||||
- BlockTurtleEggBreak
|
||||
- BlockTurtleEggCrack
|
||||
- BlockTurtleEggHatch
|
||||
- TurtleLayEgg
|
||||
- BlockTurtleEggAttack
|
||||
- BeaconActivate
|
||||
- BeaconAmbient
|
||||
- BeaconDeactivate
|
||||
- BeaconPower
|
||||
- ConduitActivate
|
||||
- ConduitAmbient
|
||||
- ConduitAttack
|
||||
- ConduitDeactivate
|
||||
- ConduitShort
|
||||
- Swoop
|
||||
- BlockBambooSaplingPlace
|
||||
- PreSneeze
|
||||
- Sneeze
|
||||
- AmbientTame
|
||||
- Scared
|
||||
- BlockScaffoldingClimb
|
||||
- CrossbowLoadingStart
|
||||
- CrossbowLoadingMiddle
|
||||
- CrossbowLoadingEnd
|
||||
- CrossbowShoot
|
||||
- CrossbowQuickChargeStart
|
||||
- CrossbowQuickChargeMiddle
|
||||
- CrossbowQuickChargeEnd
|
||||
- AmbientAggressive
|
||||
- AmbientWorried
|
||||
- CantBreed
|
||||
- ItemShieldBlock
|
||||
- ItemBookPut
|
||||
- BlockGrindstoneUse
|
||||
- BlockBellHit
|
||||
- BlockCampfireCrackle
|
||||
- Roar
|
||||
- Stun
|
||||
- BlockSweetBerryBushHurt
|
||||
- BlockSweetBerryBushPick
|
||||
- UICartographyTableTakeResult
|
||||
- UIStoneCutterTakeResult
|
||||
- BlockComposterEmpty
|
||||
- BlockComposterFill
|
||||
- BlockComposterFillSuccess
|
||||
- BlockComposterReady
|
||||
- BlockBarrelOpen
|
||||
- BlockBarrelClose
|
||||
- RaidHorn
|
||||
- BlockLoomUse
|
||||
- AmbientRaid
|
||||
- UICartographyTableUse
|
||||
- UIStoneCutterUse
|
||||
- UILoomUse
|
||||
- SmokerUse
|
||||
- BlastFurnaceUse
|
||||
- SmithingTableUse
|
||||
- Screech
|
||||
- Sleep
|
||||
- FurnaceUse
|
||||
- MooshroomConvert
|
||||
- MilkSuspiciously
|
||||
- Celebrate
|
||||
- JumpPrevent
|
||||
- AmbientPollinate
|
||||
- BeeHiveDrip
|
||||
- BeeHiveEnter
|
||||
- BeeHiveExit
|
||||
- BeeHiveWork
|
||||
- BeeHiveShear
|
||||
- HoneyBottleDrink
|
||||
- AmbientCave
|
||||
- Retreat
|
||||
- ConvertToZombified
|
||||
- Admire
|
||||
- StepLava
|
||||
- Tempt
|
||||
- Panic
|
||||
- Angry
|
||||
- AmbientWarpedForest
|
||||
- AmbientSoulsandValley
|
||||
- AmbientNetherWastes
|
||||
- AmbientBasaltDeltas
|
||||
- AmbientCrimsonForest
|
||||
- RespawnAnchorCharge
|
||||
- RespawnAnchorDeplete
|
||||
- RespawnAnchorSetSpawn
|
||||
- RespawnAnchorAmbient
|
||||
- SoulEscapeQuiet
|
||||
- SoulEscapeLoud
|
||||
- RecordPigstep
|
||||
- LinkCompassToLodestone
|
||||
- BlockSmithingTableUse
|
||||
- EquipNetherite
|
||||
- AmbientLoopWarpedForest
|
||||
- AmbientLoopSoulsandValley
|
||||
- AmbientLoopNetherWastes
|
||||
- AmbientLoopBasaltDeltas
|
||||
- AmbientLoopCrimsonForest
|
||||
- AmbientAdditionWarpedForest
|
||||
- AmbientAdditionSoulsandValley
|
||||
- AmbientAdditionNetherWastes
|
||||
- AmbientAdditionBasaltDeltas
|
||||
- AmbientAdditionCrimsonForest
|
||||
- SculkSensorPowerOn
|
||||
- SculkSensorPowerOff
|
||||
- BucketFillPowderSnow
|
||||
- BucketEmptyPowderSnow
|
||||
- PointedDripstoneCauldronDripWater
|
||||
- PointedDripstoneCauldronDripLava
|
||||
- PointedDripstoneDripWater
|
||||
- PointedDripstoneDripLava
|
||||
- CaveVinesPickBerries
|
||||
- BigDripleafTiltDown
|
||||
- BigDripleafTiltUp
|
||||
- Undefined
|
||||
|
||||
# TODO: remove?
|
||||
LegacyEntityType: li32 =>
|
||||
10: chicken
|
||||
|
|
|
|||
13
package.json
13
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "bedrock-protocol",
|
||||
"version": "3.0.0",
|
||||
"description": "Parse and serialize Minecraft Bedrock Edition packets",
|
||||
"description": "Minecraft Bedrock Edition protocol library",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "cd tools && node compileProtocol.js",
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
},
|
||||
"keywords": [
|
||||
"minecraft",
|
||||
"bedrock",
|
||||
"pocket-edition",
|
||||
"protocol"
|
||||
],
|
||||
|
|
@ -24,27 +25,25 @@
|
|||
"@jsprismarine/jsbinaryutils": "^2.1.8",
|
||||
"@xboxreplay/xboxlive-auth": "^3.3.3",
|
||||
"asn1": "^0.2.4",
|
||||
"browserify-cipher": "^1.0.1",
|
||||
"bedrock-provider": "^1.0.0",
|
||||
"debug": "^4.3.1",
|
||||
"ec-pem": "^0.18.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jsp-raknet": "github:extremeheat/raknet#client",
|
||||
"leveldb-zlib": "0.0.26",
|
||||
"minecraft-folder-path": "^1.1.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prismarine-nbt": "^1.5.0",
|
||||
"protodef": "^1.11.0",
|
||||
"raknet-native": "^1.0.0",
|
||||
"raknet-native": "^1.0.1",
|
||||
"uuid-1345": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.13.10",
|
||||
"bedrock-provider": "^1.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"buffer-equal": "^1.0.0",
|
||||
"mocha": "^8.3.2",
|
||||
"protodef-yaml": "^1.0.2",
|
||||
"protodef-yaml": "^1.0.3",
|
||||
"standard": "^16.0.3",
|
||||
"leveldb-zlib": "0.0.26",
|
||||
"bedrock-protocol": "file:."
|
||||
},
|
||||
"standard": {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default
|
|||
const BatchPacket = require('./datatypes/BatchPacket')
|
||||
const cipher = require('./transforms/encryption')
|
||||
const { EventEmitter } = require('events')
|
||||
const Versions = require('./options')
|
||||
const { Versions } = require('./options')
|
||||
const debug = require('debug')('minecraft-protocol')
|
||||
|
||||
const SKIP_BATCH = ['level_chunk', 'client_cache_blob_status', 'client_cache_miss_response']
|
||||
|
|
@ -29,19 +29,11 @@ class Connection extends EventEmitter {
|
|||
}
|
||||
|
||||
versionLessThan (version) {
|
||||
if (typeof version === 'string') {
|
||||
return Versions[version] < this.options.protocolVersion
|
||||
} else {
|
||||
return version < this.options.protocolVersion
|
||||
}
|
||||
return this.options.protocolVersion < (typeof version === 'string' ? Versions[version] : version)
|
||||
}
|
||||
|
||||
versionGreaterThan (version) {
|
||||
if (typeof version === 'string') {
|
||||
return Versions[version] > this.options.protocolVersion
|
||||
} else {
|
||||
return version > this.options.protocolVersion
|
||||
}
|
||||
return this.options.protocolVersion > (typeof version === 'string' ? Versions[version] : version)
|
||||
}
|
||||
|
||||
startEncryption (iv) {
|
||||
|
|
|
|||
|
|
@ -36,28 +36,48 @@ SizeOf.restBuffer = ['native', (value) => {
|
|||
return value.length
|
||||
}]
|
||||
|
||||
/**
|
||||
* Encapsulated data with length prefix
|
||||
*/
|
||||
Read.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => {
|
||||
return compiler.wrapCode(`
|
||||
const payloadSize = ${compiler.callType(lengthType, 'offset')}
|
||||
const { value, size } = ctx.${type}(buffer, offset + payloadSize.size)
|
||||
return { value, size: size + payloadSize.size }
|
||||
`.trim())
|
||||
}]
|
||||
Write.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => {
|
||||
return compiler.wrapCode(`
|
||||
const buf = Buffer.allocUnsafe(buffer.length - offset)
|
||||
const payloadSize = (ctx.${type})(value, buf, 0)
|
||||
let size = (ctx.${lengthType})(payloadSize, buffer, offset)
|
||||
size += buf.copy(buffer, size, 0, payloadSize)
|
||||
return size
|
||||
`.trim())
|
||||
}]
|
||||
SizeOf.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => {
|
||||
return compiler.wrapCode(`
|
||||
const payloadSize = (ctx.${type})(value)
|
||||
return (ctx.${lengthType})(payloadSize) + payloadSize
|
||||
`.trim())
|
||||
}]
|
||||
|
||||
/**
|
||||
* Read NBT until end of buffer or \0
|
||||
*/
|
||||
Read.nbtLoop = ['context', (buffer, offset) => {
|
||||
const values = []
|
||||
while (buffer[offset] != 0) {
|
||||
// console.log('offs',offset, buffer.length,buffer.slice(offset))
|
||||
const n = ctx.nbt(buffer, offset)
|
||||
// console.log('read',n)
|
||||
values.push(n.value)
|
||||
offset += n.size
|
||||
}
|
||||
// console.log('Ext',offset, buffer.length,buffer.slice(offset))
|
||||
return { value: values, size: buffer.length - offset }
|
||||
}]
|
||||
Write.nbtLoop = ['context', (value, buffer, offset) => {
|
||||
for (const val of value) {
|
||||
// console.log('val',val,offset)
|
||||
offset = ctx.nbt(val, buffer, offset)
|
||||
}
|
||||
// offset += 1
|
||||
// console.log('writing 0', offset)
|
||||
buffer.writeUint8(0, offset)
|
||||
return offset + 1
|
||||
}]
|
||||
|
|
@ -76,6 +96,10 @@ Read.nbt = ['native', minecraft.nbt[0]]
|
|||
Write.nbt = ['native', minecraft.nbt[1]]
|
||||
SizeOf.nbt = ['native', minecraft.nbt[2]]
|
||||
|
||||
Read.lnbt = ['native', minecraft.lnbt[0]]
|
||||
Write.lnbt = ['native', minecraft.lnbt[1]]
|
||||
SizeOf.lnbt = ['native', minecraft.lnbt[2]]
|
||||
|
||||
/**
|
||||
* Bits
|
||||
*/
|
||||
|
|
@ -84,7 +108,7 @@ Read.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
|||
let fstr = JSON.stringify(flags)
|
||||
if (Array.isArray(flags)) {
|
||||
fstr = '{'
|
||||
flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','))
|
||||
flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','))
|
||||
fstr += '}'
|
||||
} else if (shift) {
|
||||
fstr = '{'
|
||||
|
|
@ -106,7 +130,7 @@ Write.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
|||
let fstr = JSON.stringify(flags)
|
||||
if (Array.isArray(flags)) {
|
||||
fstr = '{'
|
||||
flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','))
|
||||
flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','))
|
||||
fstr += '}'
|
||||
} else if (shift) {
|
||||
fstr = '{'
|
||||
|
|
@ -127,7 +151,7 @@ SizeOf.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) =>
|
|||
let fstr = JSON.stringify(flags)
|
||||
if (Array.isArray(flags)) {
|
||||
fstr = '{'
|
||||
flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','))
|
||||
flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','))
|
||||
fstr += '}'
|
||||
} else if (shift) {
|
||||
fstr = '{'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
const nbt = require('prismarine-nbt')
|
||||
const UUID = require('uuid-1345')
|
||||
|
||||
const proto = nbt.protos.littleVarint
|
||||
const protoLE = nbt.protos.little
|
||||
const protoLEV = nbt.protos.littleVarint
|
||||
// TODO: deal with this:
|
||||
const zigzag = require('prismarine-nbt/compiler-zigzag')
|
||||
|
||||
|
|
@ -20,16 +21,32 @@ function writeUUID (value, buffer, offset) {
|
|||
return offset + 16
|
||||
}
|
||||
|
||||
// Little Endian + varints
|
||||
|
||||
function readNbt (buffer, offset) {
|
||||
return proto.read(buffer, offset, 'nbt')
|
||||
return protoLEV.read(buffer, offset, 'nbt')
|
||||
}
|
||||
|
||||
function writeNbt (value, buffer, offset) {
|
||||
return proto.write(value, buffer, offset, 'nbt')
|
||||
return protoLEV.write(value, buffer, offset, 'nbt')
|
||||
}
|
||||
|
||||
function sizeOfNbt (value) {
|
||||
return proto.sizeOf(value, 'nbt')
|
||||
return protoLEV.sizeOf(value, 'nbt')
|
||||
}
|
||||
|
||||
// Little Endian
|
||||
|
||||
function readNbtLE (buffer, offset) {
|
||||
return protoLE.read(buffer, offset, 'nbt')
|
||||
}
|
||||
|
||||
function writeNbtLE (value, buffer, offset) {
|
||||
return protoLE.write(value, buffer, offset, 'nbt')
|
||||
}
|
||||
|
||||
function sizeOfNbtLE (value) {
|
||||
return protoLE.sizeOf(value, 'nbt')
|
||||
}
|
||||
|
||||
function readEntityMetadata (buffer, offset, _ref) {
|
||||
|
|
@ -131,6 +148,7 @@ function sizeOfEndOfArray (value, typeArgs) {
|
|||
module.exports = {
|
||||
uuid: [readUUID, writeUUID, 16],
|
||||
nbt: [readNbt, writeNbt, sizeOfNbt],
|
||||
lnbt: [readNbtLE, writeNbtLE, sizeOfNbtLE],
|
||||
entityMetadataLoop: [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata],
|
||||
ipAddress: [readIpAddress, writeIpAddress, 4],
|
||||
endOfArray: [readEndOfArray, writeEndOfArray, sizeOfEndOfArray],
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
// Minimum supported version (< will be kicked)
|
||||
const MIN_VERSION = '1.16.201'
|
||||
// Currently supported verson
|
||||
const CURRENT_VERSION = '1.16.210'
|
||||
const CURRENT_VERSION = '1.16.220'
|
||||
|
||||
const Versions = {
|
||||
'1.16.220': 431,
|
||||
'1.16.210': 428,
|
||||
'1.16.201': 422
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,26 @@
|
|||
const { Transform } = require('readable-stream')
|
||||
const crypto = require('crypto')
|
||||
const Zlib = require('zlib')
|
||||
if (globalThis.isElectron) var { CipherCFB8 } = require('raknet-native') // eslint-disable-line
|
||||
if (globalThis.isElectron) var { CipherGCM, CipherCFB8 } = require('raknet-native') // eslint-disable-line
|
||||
|
||||
const CIPHER_ALG = 'aes-256-cfb8'
|
||||
|
||||
function createCipher (secret, initialValue) {
|
||||
if (crypto.getCiphers().includes(CIPHER_ALG)) {
|
||||
return crypto.createCipheriv(CIPHER_ALG, secret, initialValue)
|
||||
function createCipher (secret, initialValue, cipherAlgorithm) {
|
||||
if (crypto.getCiphers().includes(cipherAlgorithm)) {
|
||||
return crypto.createCipheriv(cipherAlgorithm, secret, initialValue)
|
||||
}
|
||||
return new Cipher(secret, initialValue)
|
||||
}
|
||||
|
||||
function createDecipher (secret, initialValue) {
|
||||
if (crypto.getCiphers().includes(CIPHER_ALG)) {
|
||||
return crypto.createDecipheriv(CIPHER_ALG, secret, initialValue)
|
||||
function createDecipher (secret, initialValue, cipherAlgorithm) {
|
||||
if (crypto.getCiphers().includes(cipherAlgorithm)) {
|
||||
return crypto.createDecipheriv(cipherAlgorithm, secret, initialValue)
|
||||
}
|
||||
return new Decipher(secret, initialValue)
|
||||
}
|
||||
|
||||
class Cipher extends Transform {
|
||||
constructor (secret, iv) {
|
||||
constructor (gcm, secret, iv) {
|
||||
super()
|
||||
this.aes = new CipherCFB8(secret, iv)
|
||||
this.aes = gcm ? new CipherGCM(secret, iv) : new CipherCFB8(secret, iv)
|
||||
}
|
||||
|
||||
_transform (chunk, enc, cb) {
|
||||
|
|
@ -32,9 +30,9 @@ class Cipher extends Transform {
|
|||
}
|
||||
|
||||
class Decipher extends Transform {
|
||||
constructor (secret, iv) {
|
||||
constructor (gcm, secret, iv) {
|
||||
super()
|
||||
this.aes = new CipherCFB8(secret, iv)
|
||||
this.aes = gcm ? new CipherGCM(secret, iv) : new CipherCFB8(secret, iv)
|
||||
}
|
||||
|
||||
_transform (chunk, enc, cb) {
|
||||
|
|
@ -54,7 +52,11 @@ function computeCheckSum (packetPlaintext, sendCounter, secretKeyBytes) {
|
|||
}
|
||||
|
||||
function createEncryptor (client, iv) {
|
||||
client.cipher = createCipher(client.secretKeyBytes, iv)
|
||||
if (client.versionLessThan('1.16.220')) {
|
||||
client.cipher = createCipher(client.secretKeyBytes, iv, 'aes-256-cfb8')
|
||||
} else {
|
||||
client.cipher = createCipher(client.secretKeyBytes, iv.slice(0, 12), 'aes-256-gcm')
|
||||
}
|
||||
client.sendCounter = client.sendCounter || 0n
|
||||
|
||||
// A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]).
|
||||
|
|
@ -77,18 +79,21 @@ function createEncryptor (client, iv) {
|
|||
}
|
||||
|
||||
function createDecryptor (client, iv) {
|
||||
client.decipher = createDecipher(client.secretKeyBytes, iv)
|
||||
if (client.versionLessThan('1.16.220')) {
|
||||
client.decipher = createDecipher(client.secretKeyBytes, iv, 'aes-256-cfb8')
|
||||
} else {
|
||||
client.decipher = createDecipher(client.secretKeyBytes, iv.slice(0, 12), 'aes-256-gcm')
|
||||
}
|
||||
|
||||
client.receiveCounter = client.receiveCounter || 0n
|
||||
|
||||
function verify (chunk) {
|
||||
// console.log('Decryptor: checking checksum', client.receiveCounter, chunk)
|
||||
const packet = chunk.slice(0, chunk.length - 8)
|
||||
const checksum = chunk.slice(chunk.length - 8, chunk.length)
|
||||
const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes)
|
||||
client.receiveCounter++
|
||||
|
||||
if (Buffer.compare(checksum, computedCheckSum) !== 0) {
|
||||
// console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex'))
|
||||
throw Error(`Checksum mismatch ${checksum.toString('hex')} != ${computedCheckSum.toString('hex')}`)
|
||||
}
|
||||
|
||||
|
|
@ -108,17 +113,3 @@ function createDecryptor (client, iv) {
|
|||
module.exports = {
|
||||
createCipher, createDecipher, createEncryptor, createDecryptor
|
||||
}
|
||||
|
||||
// function testDecrypt () {
|
||||
// const client = {
|
||||
// secretKeyBytes: Buffer.from('ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=', 'base64'),
|
||||
// onDecryptedPacket: (...data) => console.log('Decrypted', data)
|
||||
// }
|
||||
// const iv = Buffer.from('ZOBpyzki/M8UZv5tiBih0w==', 'base64')
|
||||
|
||||
// const decrypt = createDecryptor(client, iv)
|
||||
// console.log('Dec', decrypt(Buffer.from('4B4FCA0C2A4114155D67F8092154AAA5EF', 'hex')))
|
||||
// console.log('Dec 2', decrypt(Buffer.from('DF53B9764DB48252FA1AE3AEE4', 'hex')))
|
||||
// }
|
||||
|
||||
// testDecrypt()
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
// process.env.DEBUG = 'minecraft-protocol raknet'
|
||||
const { Server, Client } = require('../')
|
||||
const { dumpPackets, hasDumps } = require('../tools/genPacketDumps')
|
||||
const { dumpPackets } = require('../tools/genPacketDumps')
|
||||
const DataProvider = require('../data/provider')
|
||||
|
||||
// First we need to dump some packets that a vanilla server would send a vanilla
|
||||
// client. Then we can replay those back in our custom server.
|
||||
function prepare (version) {
|
||||
if (!hasDumps(version)) {
|
||||
return dumpPackets(version)
|
||||
}
|
||||
return dumpPackets(version)
|
||||
}
|
||||
|
||||
async function startTest (version = '1.16.210', ok) {
|
||||
async function startTest (version = '1.16.201', ok) {
|
||||
await prepare(version)
|
||||
const Item = require('../types/Item')(version)
|
||||
const port = 19130
|
||||
|
|
@ -36,7 +34,7 @@ async function startTest (version = '1.16.210', ok) {
|
|||
// server logic
|
||||
server.on('connect', client => {
|
||||
client.on('join', () => {
|
||||
console.log('Client joined', client.getData())
|
||||
console.log('Client joined server', client.getData())
|
||||
|
||||
client.write('resource_packs_info', {
|
||||
must_accept: false,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/* eslint-env jest */
|
||||
|
||||
const { timedTest } = require('./internal')
|
||||
const { Versions } = require('../src/options')
|
||||
|
||||
describe('internal client/server test', function () {
|
||||
this.timeout(120 * 1000)
|
||||
|
||||
it('connects', async () => {
|
||||
await timedTest()
|
||||
for (const version in Versions) {
|
||||
console.debug(version)
|
||||
await timedTest(version)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ const vanillaServer = require('../tools/startVanillaServer')
|
|||
const { Client } = require('../src/client')
|
||||
const { waitFor } = require('../src/datatypes/util')
|
||||
const { ChunkColumn, Version } = require('bedrock-provider')
|
||||
const { CURRENT_VERSION } = require('../src/options')
|
||||
|
||||
async function test (version) {
|
||||
// Start the server, wait for it to accept clients, throws on timeout
|
||||
const handle = await vanillaServer.startServerAndWait(version, 1000 * 120)
|
||||
const handle = await vanillaServer.startServerAndWait(version, 1000 * 220)
|
||||
console.log('Started server')
|
||||
|
||||
const client = new Client({
|
||||
|
|
@ -65,5 +66,5 @@ async function test (version) {
|
|||
clearInterval(loop)
|
||||
}
|
||||
|
||||
if (!module.parent) test()
|
||||
if (!module.parent) test(CURRENT_VERSION)
|
||||
module.exports = { clientTest: test }
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ function createProtocol () {
|
|||
function copyLatest () {
|
||||
process.chdir(join(__dirname, '/../data/latest'))
|
||||
const version = genProtoSchema()
|
||||
try { fs.mkdirSync(`../${version}`) } catch {}
|
||||
fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: getJSON('./proto.json') }, null, 2))
|
||||
fs.unlinkSync('./proto.json') // remove temp file
|
||||
fs.unlinkSync('./packet_map.yml') // remove temp file
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ async function dump (version, force) {
|
|||
const client = new Client({
|
||||
hostname: '127.0.0.1',
|
||||
port,
|
||||
version,
|
||||
username: 'Boat' + random,
|
||||
offline: true
|
||||
})
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ async function download (os, version, path = 'bds-') {
|
|||
get(found, 'bds.zip')
|
||||
console.info('⚡ Unzipping')
|
||||
// Unzip server
|
||||
if (process.platform === 'linux') cp.execSync('unzip bds.zip')
|
||||
if (process.platform === 'linux') cp.execSync('unzip bds.zip && chmod +777 ./bedrock_server')
|
||||
else cp.execSync('tar -xf bds.zip')
|
||||
return verStr
|
||||
}
|
||||
|
|
@ -83,7 +83,11 @@ async function startServer (version, onStart, options = {}) {
|
|||
configure(options)
|
||||
const handle = run(!onStart)
|
||||
if (onStart) {
|
||||
handle.stdout.on('data', data => data.includes('Server started.') ? onStart() : null)
|
||||
let stdout = ''
|
||||
handle.stdout.on('data', data => {
|
||||
stdout += data
|
||||
if (stdout.includes('Server started')) onStart()
|
||||
})
|
||||
handle.stdout.pipe(process.stdout)
|
||||
handle.stderr.pipe(process.stdout)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,26 +11,52 @@ module.exports = (version) =>
|
|||
}
|
||||
|
||||
static fromBedrock (obj) {
|
||||
return new Item({
|
||||
runtimeId: obj.runtime_id,
|
||||
networkId: obj.item?.network_id,
|
||||
count: obj.item?.auxiliary_value & 0xff,
|
||||
metadata: obj.item?.auxiliary_value >> 8,
|
||||
nbt: obj.item?.nbt?.nbt
|
||||
})
|
||||
if (version === '1.16.220') {
|
||||
return new Item({
|
||||
networkId: obj.network_id,
|
||||
stackId: obj.stack_id,
|
||||
blockRuntimeId: obj.block_runtime_id,
|
||||
count: obj.count,
|
||||
metadata: obj.metadata,
|
||||
nbt: obj.extra.nbt
|
||||
})
|
||||
} else {
|
||||
return new Item({
|
||||
networkId: obj.runtime_id,
|
||||
sackId: obj.item?.network_id,
|
||||
count: obj.item?.auxiliary_value & 0xff,
|
||||
metadata: obj.item?.auxiliary_value >> 8,
|
||||
nbt: obj.item?.nbt?.nbt
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
toBedrock () {
|
||||
return {
|
||||
runtime_id: this.runtimeId,
|
||||
item: {
|
||||
if (version === '1.16.220') {
|
||||
return {
|
||||
network_id: this.networkId,
|
||||
auxiliary_value: (this.metadata << 8) | (this.count & 0xff),
|
||||
has_nbt: !!this.nbt,
|
||||
nbt: { version: 1, nbt: this.nbt },
|
||||
can_place_on: [],
|
||||
can_destroy: [],
|
||||
blocking_tick: 0
|
||||
count: this.count,
|
||||
metadata: this.metadata,
|
||||
extra: {
|
||||
has_nbt: !!this.nbt,
|
||||
nbt: { version: 1, nbt: this.nbt },
|
||||
can_place_on: [],
|
||||
can_destroy: [],
|
||||
blocking_tick: 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
runtime_id: this.runtimeId,
|
||||
item: {
|
||||
network_id: this.networkId,
|
||||
auxiliary_value: (this.metadata << 8) | (this.count & 0xff),
|
||||
has_nbt: !!this.nbt,
|
||||
nbt: { version: 1, nbt: this.nbt },
|
||||
can_place_on: [],
|
||||
can_destroy: [],
|
||||
blocking_tick: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue