1.16.4 (754) / 1.16.3 (753) / 1.16.2 (751) protocol (#390)
Adds support for 1.16.4 (754) / 1.16.3 (753) / 1.16.2 (751) protocols * Update packet IDs and readme * Add and handle ChunkData_Biomes3D_VarInt variant * Support world chunk data padded bit map array * Add and handle JoinGame_WorldNames_IsHard variant * Add and handle MultiBlockChange_Packed variant * Add UnlockRecipes_WithBlastSmoker variant * Add SetDisplayedRecipe and SetRecipeBookState packets
This commit is contained in:
parent
f4414e7814
commit
4a757656ab
|
@ -23,6 +23,9 @@ Join with your favorite IRC client.
|
|||
|
||||
| Game version | Protocol version | Supported? |
|
||||
| ------ | --- | --- |
|
||||
| 1.16.4 | 754 | ✓ |
|
||||
| 1.16.3 | 753 | ✓ |
|
||||
| 1.16.2 | 751 | ✓ |
|
||||
| 1.16.1 | 736 | ✓ |
|
||||
| 1.16 | 735 | ✓ |
|
||||
| 1.15.2 | 578 | ✓ |
|
||||
|
|
|
@ -40,9 +40,9 @@ use std::net::TcpStream;
|
|||
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub const SUPPORTED_PROTOCOLS: [i32; 21] = [
|
||||
736, 735, 578, 575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74,
|
||||
47, 5,
|
||||
pub const SUPPORTED_PROTOCOLS: [i32; 24] = [
|
||||
754, 753, 751, 736, 735, 578, 575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210,
|
||||
109, 107, 74, 47, 5,
|
||||
];
|
||||
|
||||
static CURRENT_PROTOCOL_VERSION: AtomicI32 = AtomicI32::new(SUPPORTED_PROTOCOLS[0]);
|
||||
|
@ -1156,6 +1156,8 @@ impl Conn {
|
|||
let pos = buf.position() as usize;
|
||||
let ibuf = buf.into_inner();
|
||||
if ibuf.len() != pos {
|
||||
debug!("pos = {:?}", pos);
|
||||
debug!("ibuf = {:?}", ibuf);
|
||||
return Result::Err(Error::Err(format!(
|
||||
"Failed to read all of packet 0x{:X}, \
|
||||
had {} bytes left",
|
||||
|
|
|
@ -353,6 +353,16 @@ state_packets!(
|
|||
field crafting_book_open: bool = when(|p: &CraftingBookData| p.action.0 == 1),
|
||||
field crafting_filter: bool = when(|p: &CraftingBookData| p.action.0 == 1),
|
||||
}
|
||||
/// SetDisplayedRecipe replaces CraftingBookData, type 0.
|
||||
packet SetDisplayedRecipe {
|
||||
field recipe_id: String =,
|
||||
}
|
||||
/// SetRecipeBookState replaces CraftingBookData, type 1.
|
||||
packet SetRecipeBookState {
|
||||
field book_id: VarInt =, // TODO: enum, 0: crafting, 1: furnace, 2: blast furnace, 3: smoker
|
||||
field book_open: bool =,
|
||||
field filter_active: bool =,
|
||||
}
|
||||
packet NameItem {
|
||||
field item_name: String =,
|
||||
}
|
||||
|
@ -881,6 +891,11 @@ state_packets!(
|
|||
field message: format::Component =,
|
||||
}
|
||||
/// MultiBlockChange is used to update a batch of blocks in a single packet.
|
||||
packet MultiBlockChange_Packed {
|
||||
field chunk_section_pos: u64 =,
|
||||
field no_trust_edges: bool =,
|
||||
field records: LenPrefixed<VarInt, VarLong> =,
|
||||
}
|
||||
packet MultiBlockChange_VarInt {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
|
@ -1047,6 +1062,16 @@ state_packets!(
|
|||
}
|
||||
/// ChunkData sends or updates a single chunk on the client. If New is set
|
||||
/// then biome data should be sent too.
|
||||
packet ChunkData_Biomes3D_VarInt {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
field new: bool =,
|
||||
field bitmask: VarInt =,
|
||||
field heightmaps: Option<nbt::NamedTag> =,
|
||||
field biomes: LenPrefixed<VarInt, VarInt> = when(|p: &ChunkData_Biomes3D_VarInt| p.new),
|
||||
field data: LenPrefixedBytes<VarInt> =,
|
||||
field block_entities: LenPrefixed<VarInt, Option<nbt::NamedTag>> =,
|
||||
}
|
||||
packet ChunkData_Biomes3D_bool {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
|
@ -1200,6 +1225,39 @@ state_packets!(
|
|||
}
|
||||
/// JoinGame is sent after completing the login process. This
|
||||
/// sets the initial state for the client.
|
||||
packet JoinGame_WorldNames_IsHard {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
/// Whether hardcore mode is enabled
|
||||
field is_hardcore: bool =,
|
||||
/// The starting gamemode of the client
|
||||
field gamemode: u8 =,
|
||||
/// The previous gamemode of the client
|
||||
field previous_gamemode: u8 =,
|
||||
/// Identifiers for all worlds on the server
|
||||
field world_names: LenPrefixed<VarInt, String> =,
|
||||
/// Represents a dimension registry
|
||||
field dimension_codec: Option<nbt::NamedTag> =,
|
||||
/// The dimension the client is starting in
|
||||
field dimension: Option<nbt::NamedTag> =,
|
||||
/// The world being spawned into
|
||||
field world_name: String =,
|
||||
/// Truncated SHA-256 hash of world's seed
|
||||
field hashed_seed: i64 =,
|
||||
/// The max number of players on the server
|
||||
field max_players: VarInt =,
|
||||
/// The render distance (2-32)
|
||||
field view_distance: VarInt =,
|
||||
/// Whether the client should reduce the amount of debug
|
||||
/// information it displays in F3 mode
|
||||
field reduced_debug_info: bool =,
|
||||
/// Whether to prompt or immediately respawn
|
||||
field enable_respawn_screen: bool =,
|
||||
/// Whether the world is in debug mode
|
||||
field is_debug: bool =,
|
||||
/// Whether the world is a superflat world
|
||||
field is_flat: bool =,
|
||||
}
|
||||
packet JoinGame_WorldNames {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
|
@ -1231,7 +1289,6 @@ state_packets!(
|
|||
/// Whether the world is a superflat world
|
||||
field is_flat: bool =,
|
||||
}
|
||||
|
||||
packet JoinGame_HashedSeed_Respawn {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
|
@ -1527,6 +1584,19 @@ state_packets!(
|
|||
field recipe_ids: LenPrefixed<VarInt, String> =,
|
||||
field recipe_ids2: LenPrefixed<VarInt, String> = when(|p: &UnlockRecipes_WithSmelting| p.action.0 == 0),
|
||||
}
|
||||
packet UnlockRecipes_WithBlastSmoker {
|
||||
field action: VarInt =,
|
||||
field crafting_book_open: bool =,
|
||||
field filtering_craftable: bool =,
|
||||
field smelting_book_open: bool =,
|
||||
field filtering_smeltable: bool =,
|
||||
field blast_furnace_open: bool =,
|
||||
field filtering_blast_furnace: bool =,
|
||||
field smoker_open: bool =,
|
||||
field filtering_smoker: bool =,
|
||||
field recipe_ids: LenPrefixed<VarInt, String> =,
|
||||
field recipe_ids2: LenPrefixed<VarInt, String> = when(|p: &UnlockRecipes_WithBlastSmoker| p.action.0 == 0),
|
||||
}
|
||||
/// EntityDestroy destroys the entities with the ids in the provided slice.
|
||||
packet EntityDestroy {
|
||||
field entity_ids: LenPrefixed<VarInt, VarInt> =,
|
||||
|
|
|
@ -14,6 +14,7 @@ mod v1_14_3;
|
|||
mod v1_14_4;
|
||||
mod v1_15;
|
||||
mod v1_16_1;
|
||||
mod v1_16_4;
|
||||
mod v1_7_10;
|
||||
mod v1_8_9;
|
||||
mod v1_9;
|
||||
|
@ -25,6 +26,9 @@ mod v1_9_2;
|
|||
pub fn protocol_name_to_protocol_version(s: String) -> i32 {
|
||||
match s.as_ref() {
|
||||
"" => SUPPORTED_PROTOCOLS[0],
|
||||
"1.16.4" => 754,
|
||||
"1.16.3" => 753,
|
||||
"1.16.2" => 751,
|
||||
"1.16.1" => 736,
|
||||
"1.16" => 735,
|
||||
"1.15.2" => 578,
|
||||
|
@ -64,6 +68,7 @@ pub fn translate_internal_packet_id_for_version(
|
|||
to_internal: bool,
|
||||
) -> i32 {
|
||||
match version {
|
||||
754 | 753 | 751 => v1_16_4::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
736 => v1_16_1::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
735 => v1_16_1::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
578 => v1_15::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity_Sneakflag
|
||||
0x0f => GenerateStructure
|
||||
0x10 => KeepAliveServerbound_i64
|
||||
0x11 => LockDifficulty
|
||||
0x12 => PlayerPosition
|
||||
0x13 => PlayerPositionLook
|
||||
0x14 => PlayerLook
|
||||
0x15 => Player
|
||||
0x16 => VehicleMove
|
||||
0x17 => SteerBoat
|
||||
0x18 => PickItem
|
||||
0x19 => CraftRecipeRequest
|
||||
0x1a => ClientAbilities_u8
|
||||
0x1b => PlayerDigging
|
||||
0x1c => PlayerAction
|
||||
0x1d => SteerVehicle
|
||||
0x1e => SetDisplayedRecipe
|
||||
0x1f => SetRecipeBookState
|
||||
0x20 => NameItem
|
||||
0x21 => ResourcePackStatus
|
||||
0x22 => AdvancementTab
|
||||
0x23 => SelectTrade
|
||||
0x24 => SetBeaconEffect
|
||||
0x25 => HeldItemChange
|
||||
0x26 => UpdateCommandBlock
|
||||
0x27 => UpdateCommandBlockMinecart
|
||||
0x28 => CreativeInventoryAction
|
||||
0x29 => UpdateJigsawBlock_Joint
|
||||
0x2a => UpdateStructureBlock
|
||||
0x2b => SetSign
|
||||
0x2c => ArmSwing
|
||||
0x2d => SpectateTeleport
|
||||
0x2e => PlayerBlockPlacement_insideblock
|
||||
0x2f => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject_VarInt
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnMob_NoMeta
|
||||
0x03 => SpawnPainting_VarInt
|
||||
0x04 => SpawnPlayer_f64_NoMeta
|
||||
0x05 => Animation
|
||||
0x06 => Statistics
|
||||
0x07 => AcknowledgePlayerDigging
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage_Sender
|
||||
0x0f => TabCompleteReply
|
||||
0x10 => DeclareCommands
|
||||
0x11 => ConfirmTransaction
|
||||
0x12 => WindowClose
|
||||
0x13 => WindowItems
|
||||
0x14 => WindowProperty
|
||||
0x15 => WindowSetSlot
|
||||
0x16 => SetCooldown
|
||||
0x17 => PluginMessageClientbound
|
||||
0x18 => NamedSoundEffect
|
||||
0x19 => Disconnect
|
||||
0x1a => EntityAction
|
||||
0x1b => Explosion
|
||||
0x1c => ChunkUnload
|
||||
0x1d => ChangeGameState
|
||||
0x1e => WindowOpenHorse
|
||||
0x1f => KeepAliveClientbound_i64
|
||||
0x20 => ChunkData_Biomes3D_VarInt
|
||||
0x21 => Effect
|
||||
0x22 => Particle_f64
|
||||
0x23 => UpdateLight_WithTrust
|
||||
0x24 => JoinGame_WorldNames_IsHard
|
||||
0x25 => Maps
|
||||
0x26 => TradeList_WithRestock
|
||||
0x27 => EntityMove_i16
|
||||
0x28 => EntityLookAndMove_i16
|
||||
0x29 => EntityLook_VarInt
|
||||
0x2a => Entity
|
||||
0x2b => VehicleTeleport
|
||||
0x2c => OpenBook
|
||||
0x2d => WindowOpen_VarInt
|
||||
0x2e => SignEditorOpen
|
||||
0x2f => CraftRecipeResponse
|
||||
0x30 => PlayerAbilities
|
||||
0x31 => CombatEvent
|
||||
0x32 => PlayerInfo
|
||||
0x33 => FacePlayer
|
||||
0x34 => TeleportPlayer_WithConfirm
|
||||
0x35 => UnlockRecipes_WithBlastSmoker
|
||||
0x36 => EntityDestroy
|
||||
0x37 => EntityRemoveEffect
|
||||
0x38 => ResourcePackSend
|
||||
0x39 => Respawn_WorldName
|
||||
0x3a => EntityHeadLook
|
||||
0x3b => MultiBlockChange_Packed
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => SpawnPosition
|
||||
0x43 => ScoreboardDisplay
|
||||
0x44 => EntityMetadata
|
||||
0x45 => EntityAttach
|
||||
0x46 => EntityVelocity
|
||||
0x47 => EntityEquipment_VarInt // TODO: changed to an array, but earlier than 1.16.1
|
||||
0x48 => SetExperience
|
||||
0x49 => UpdateHealth
|
||||
0x4a => ScoreboardObjective
|
||||
0x4b => SetPassengers
|
||||
0x4c => Teams_VarInt
|
||||
0x4d => UpdateScore
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess_UUID
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -16,6 +16,7 @@ pub struct Map {
|
|||
bits: Vec<u64>,
|
||||
pub bit_size: usize,
|
||||
length: usize,
|
||||
padded: bool,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -53,17 +54,20 @@ impl Map {
|
|||
bit_size: size,
|
||||
length: len,
|
||||
bits: Vec::with_capacity((len * size) / 64),
|
||||
padded: false,
|
||||
};
|
||||
for _ in 0..len {
|
||||
map.bits.push(0)
|
||||
}
|
||||
map
|
||||
}
|
||||
pub fn from_raw(bits: Vec<u64>, size: usize) -> Map {
|
||||
|
||||
pub fn from_raw(bits: Vec<u64>, size: usize, padded: bool) -> Map {
|
||||
Map {
|
||||
length: (bits.len() * 64 + (size - 1)) / size,
|
||||
bit_size: size,
|
||||
bits,
|
||||
padded,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,8 +79,17 @@ impl Map {
|
|||
n
|
||||
}
|
||||
|
||||
fn get_bit_offset(&self, i: usize) -> usize {
|
||||
let padding = if self.padded {
|
||||
i / (64 / self.bit_size) * (64 % self.bit_size)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
i * self.bit_size + padding
|
||||
}
|
||||
|
||||
pub fn set(&mut self, i: usize, val: usize) {
|
||||
let i = i * self.bit_size;
|
||||
let i = self.get_bit_offset(i);
|
||||
let pos = i / 64;
|
||||
let mask = (1u64 << self.bit_size) - 1;
|
||||
let ii = i % 64;
|
||||
|
@ -90,7 +103,7 @@ impl Map {
|
|||
}
|
||||
|
||||
pub fn get(&self, i: usize) -> usize {
|
||||
let i = i * self.bit_size;
|
||||
let i = self.get_bit_offset(i);
|
||||
let pos = i / 64;
|
||||
let mask = (1 << self.bit_size) - 1;
|
||||
let ii = i % 64;
|
||||
|
|
|
@ -509,6 +509,7 @@ impl Server {
|
|||
self pck {
|
||||
PluginMessageClientbound_i16 => on_plugin_message_clientbound_i16,
|
||||
PluginMessageClientbound => on_plugin_message_clientbound_1,
|
||||
JoinGame_WorldNames_IsHard => on_game_join_worldnames_ishard,
|
||||
JoinGame_WorldNames => on_game_join_worldnames,
|
||||
JoinGame_HashedSeed_Respawn => on_game_join_hashedseed_respawn,
|
||||
JoinGame_i32_ViewDistance => on_game_join_i32_viewdistance,
|
||||
|
@ -521,6 +522,7 @@ impl Server {
|
|||
KeepAliveClientbound_i64 => on_keep_alive_i64,
|
||||
KeepAliveClientbound_VarInt => on_keep_alive_varint,
|
||||
KeepAliveClientbound_i32 => on_keep_alive_i32,
|
||||
ChunkData_Biomes3D_VarInt => on_chunk_data_biomes3d_varint,
|
||||
ChunkData_Biomes3D_bool => on_chunk_data_biomes3d_bool,
|
||||
ChunkData => on_chunk_data,
|
||||
ChunkData_Biomes3D => on_chunk_data_biomes3d,
|
||||
|
@ -533,6 +535,7 @@ impl Server {
|
|||
ChunkUnload => on_chunk_unload,
|
||||
BlockChange_VarInt => on_block_change_varint,
|
||||
BlockChange_u8 => on_block_change_u8,
|
||||
MultiBlockChange_Packed => on_multi_block_change_packed,
|
||||
MultiBlockChange_VarInt => on_multi_block_change_varint,
|
||||
MultiBlockChange_u16 => on_multi_block_change_u16,
|
||||
TeleportPlayer_WithConfirm => on_teleport_player_withconfirm,
|
||||
|
@ -970,6 +973,13 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_game_join_worldnames_ishard(
|
||||
&mut self,
|
||||
join: packet::play::clientbound::JoinGame_WorldNames_IsHard,
|
||||
) {
|
||||
self.on_game_join(join.gamemode, join.entity_id)
|
||||
}
|
||||
|
||||
fn on_game_join_worldnames(&mut self, join: packet::play::clientbound::JoinGame_WorldNames) {
|
||||
self.on_game_join(join.gamemode, join.entity_id)
|
||||
}
|
||||
|
@ -1777,6 +1787,22 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_chunk_data_biomes3d_varint(
|
||||
&mut self,
|
||||
chunk_data: packet::play::clientbound::ChunkData_Biomes3D_VarInt,
|
||||
) {
|
||||
self.world
|
||||
.load_chunk115(
|
||||
chunk_data.chunk_x,
|
||||
chunk_data.chunk_z,
|
||||
chunk_data.new,
|
||||
chunk_data.bitmask.0 as u16,
|
||||
chunk_data.data.data,
|
||||
)
|
||||
.unwrap();
|
||||
self.load_block_entities(chunk_data.block_entities.data);
|
||||
}
|
||||
|
||||
fn on_chunk_data_biomes3d_bool(
|
||||
&mut self,
|
||||
chunk_data: packet::play::clientbound::ChunkData_Biomes3D_bool,
|
||||
|
@ -1934,6 +1960,31 @@ impl Server {
|
|||
);
|
||||
}
|
||||
|
||||
fn on_multi_block_change_packed(
|
||||
&mut self,
|
||||
block_change: packet::play::clientbound::MultiBlockChange_Packed,
|
||||
) {
|
||||
let sx = (block_change.chunk_section_pos >> 42) as i32;
|
||||
let sy = ((block_change.chunk_section_pos << 44) >> 44) as i32;
|
||||
let sz = ((block_change.chunk_section_pos << 22) >> 42) as i32;
|
||||
|
||||
for record in block_change.records.data {
|
||||
let block_raw_id = record.0 >> 12;
|
||||
let lz = (record.0 & 0xf) as i32;
|
||||
let ly = ((record.0 >> 4) & 0xf) as i32;
|
||||
let lx = ((record.0 >> 8) & 0xf) as i32;
|
||||
|
||||
self.world.set_block(
|
||||
Position::new(sx + lx as i32, sy + ly as i32, sz + lz as i32),
|
||||
block::Block::by_vanilla_id(
|
||||
block_raw_id as usize,
|
||||
self.protocol_version,
|
||||
&self.world.modded_block_ids,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_multi_block_change_varint(
|
||||
&mut self,
|
||||
block_change: packet::play::clientbound::MultiBlockChange_VarInt,
|
||||
|
|
|
@ -1066,7 +1066,8 @@ impl World {
|
|||
}
|
||||
|
||||
let bits = LenPrefixed::<VarInt, u64>::read_from(&mut data)?.data;
|
||||
let m = bit::Map::from_raw(bits, bit_size as usize);
|
||||
let padded = self.protocol_version >= 736;
|
||||
let m = bit::Map::from_raw(bits, bit_size as usize, padded);
|
||||
|
||||
for bi in 0..4096 {
|
||||
let id = m.get(bi);
|
||||
|
|
Loading…
Reference in New Issue