diff --git a/README.md b/README.md index aa82d3a..1830863 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Discussion forum: [https://github.com/iceiix/stevenarella/discussions](https://g | Game version | Protocol version | Supported? | | ------ | --- | --- | +| 1.18.1 | 757 | ✓ | | 1.17.1 | 756 | ✓ | | 1.16.5 | 754 | ✓ | | 1.16.4 | 754 | ✓ | diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 1c8ad36..66cb75e 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -39,9 +39,9 @@ use std::io::{Read, Write}; use std::net::TcpStream; use std::sync::atomic::{AtomicBool, AtomicI32, Ordering}; -pub const SUPPORTED_PROTOCOLS: [i32; 25] = [ - 756, 754, 753, 751, 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; 26] = [ + 757, 756, 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]); diff --git a/protocol/src/protocol/packet.rs b/protocol/src/protocol/packet.rs index baee55f..7f5f537 100644 --- a/protocol/src/protocol/packet.rs +++ b/protocol/src/protocol/packet.rs @@ -835,7 +835,12 @@ state_packets!( } /// UpdateBlockEntity updates the nbt tag of a block entity in the /// world. - packet UpdateBlockEntity { + packet UpdateBlockEntity_VarInt { + field location: Position =, + field action: VarInt =, + field nbt: Option =, + } + packet UpdateBlockEntity_u8 { field location: Position =, field action: u8 =, field nbt: Option =, @@ -1132,6 +1137,21 @@ 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_AndLight { + field chunk_x: i32 =, + field chunk_z: i32 =, + field heightmaps: Option =, + field data: LenPrefixedBytes =, + field block_entities: LenPrefixed =, + + field trust_edges: bool =, + field sky_light_mask: LenPrefixed =, + field block_light_mask: LenPrefixed =, + field empty_sky_light_mask: LenPrefixed =, + field empty_block_light_mask: LenPrefixed =, + field sky_light_arrays: LenPrefixed> =, + field block_light_arrays: LenPrefixed> =, + } packet ChunkData_Biomes3D_Bitmasks { field chunk_x: i32 =, field chunk_z: i32 =, @@ -1324,6 +1344,41 @@ state_packets!( } /// JoinGame is sent after completing the login process. This /// sets the initial state for the client. + packet JoinGame_WorldNames_IsHard_SimDist { + /// 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 =, + /// Represents a dimension registry + field dimension_codec: Option =, + /// The dimension the client is starting in + field dimension: Option =, + /// 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 =, + /// The distance the client will process entities + field simulation_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_IsHard { /// The entity id the client will be referenced by field entity_id: i32 =, @@ -2019,6 +2074,10 @@ state_packets!( field object_name: String =, field value: Option = when(|p: &UpdateScore_i32| p.action != 1), } + /// UpdateSimulationDistance is used to set how far the client will process entities. + packet UpdateSimulationDistance { + field simulation_distance: VarInt =, + } /// SpawnPosition is sent to change the player's current spawn point. Currently /// only used by the client for the compass. packet SpawnPosition_Angle { @@ -2714,6 +2773,34 @@ impl Serializable for CriterionProgress { } } +#[derive(Debug, Default, Clone, PartialEq)] +pub struct BlockEntityAtPackedLocation { + /// The packed section coordinates, calculated from ((blockX & 15) << 4) | (blockZ & 15) + pub packed_xz: u8, + /// The height relative to the world + pub y: i16, + pub ty: VarInt, + pub data: Option, +} + +impl Serializable for BlockEntityAtPackedLocation { + fn read_from(buf: &mut R) -> Result { + Ok(BlockEntityAtPackedLocation { + packed_xz: Serializable::read_from(buf)?, + y: Serializable::read_from(buf)?, + ty: Serializable::read_from(buf)?, + data: Serializable::read_from(buf)?, + }) + } + + fn write_to(&self, buf: &mut W) -> Result<(), Error> { + self.packed_xz.write_to(buf)?; + self.y.write_to(buf)?; + self.ty.write_to(buf)?; + self.data.write_to(buf) + } +} + #[derive(Debug, Default, Clone, PartialEq)] pub struct EntityEquipment { pub slot: u8, diff --git a/protocol/src/protocol/versions.rs b/protocol/src/protocol/versions.rs index 016b607..49b4eb7 100644 --- a/protocol/src/protocol/versions.rs +++ b/protocol/src/protocol/versions.rs @@ -16,6 +16,7 @@ mod v1_15; mod v1_16_1; mod v1_16_4; mod v1_17_1; +mod v1_18_1; mod v1_7_10; mod v1_8_9; mod v1_9; @@ -27,6 +28,7 @@ mod v1_9_2; pub fn protocol_name_to_protocol_version(s: String) -> i32 { match s.as_ref() { "" => SUPPORTED_PROTOCOLS[0], + "1.18.1" => 757, "1.17.1" => 756, "1.16.5" => 754, "1.16.4" => 754, @@ -71,6 +73,7 @@ pub fn translate_internal_packet_id_for_version( to_internal: bool, ) -> i32 { match version { + 757 => v1_18_1::translate_internal_packet_id(state, dir, id, to_internal), 756 => v1_17_1::translate_internal_packet_id(state, dir, id, to_internal), 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), diff --git a/protocol/src/protocol/versions/v15w39c.rs b/protocol/src/protocol/versions/v15w39c.rs index a822dc5..a1a941f 100644 --- a/protocol/src/protocol/versions/v15w39c.rs +++ b/protocol/src/protocol/versions/v15w39c.rs @@ -46,7 +46,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v18w50a.rs b/protocol/src/protocol/versions/v18w50a.rs index fbdc186..d9be84b 100644 --- a/protocol/src/protocol/versions/v18w50a.rs +++ b/protocol/src/protocol/versions/v18w50a.rs @@ -62,7 +62,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v19w02a.rs b/protocol/src/protocol/versions/v19w02a.rs index b63cff4..22ba2ee 100644 --- a/protocol/src/protocol/versions/v19w02a.rs +++ b/protocol/src/protocol/versions/v19w02a.rs @@ -62,7 +62,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_10_2.rs b/protocol/src/protocol/versions/v1_10_2.rs index 82169db..35ab46d 100644 --- a/protocol/src/protocol/versions/v1_10_2.rs +++ b/protocol/src/protocol/versions/v1_10_2.rs @@ -49,7 +49,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_11_2.rs b/protocol/src/protocol/versions/v1_11_2.rs index a2fb19b..188ebfe 100644 --- a/protocol/src/protocol/versions/v1_11_2.rs +++ b/protocol/src/protocol/versions/v1_11_2.rs @@ -49,7 +49,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_12_2.rs b/protocol/src/protocol/versions/v1_12_2.rs index 363fe1c..02cc2fe 100644 --- a/protocol/src/protocol/versions/v1_12_2.rs +++ b/protocol/src/protocol/versions/v1_12_2.rs @@ -52,7 +52,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_13_2.rs b/protocol/src/protocol/versions/v1_13_2.rs index d2cf0b3..e164ff1 100644 --- a/protocol/src/protocol/versions/v1_13_2.rs +++ b/protocol/src/protocol/versions/v1_13_2.rs @@ -62,7 +62,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_14.rs b/protocol/src/protocol/versions/v1_14.rs index ccf10e6..3cab659 100644 --- a/protocol/src/protocol/versions/v1_14.rs +++ b/protocol/src/protocol/versions/v1_14.rs @@ -65,7 +65,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_14_1.rs b/protocol/src/protocol/versions/v1_14_1.rs index ccf10e6..3cab659 100644 --- a/protocol/src/protocol/versions/v1_14_1.rs +++ b/protocol/src/protocol/versions/v1_14_1.rs @@ -65,7 +65,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_14_2.rs b/protocol/src/protocol/versions/v1_14_2.rs index ccf10e6..3cab659 100644 --- a/protocol/src/protocol/versions/v1_14_2.rs +++ b/protocol/src/protocol/versions/v1_14_2.rs @@ -65,7 +65,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_14_3.rs b/protocol/src/protocol/versions/v1_14_3.rs index ed92aa7..39081ee 100644 --- a/protocol/src/protocol/versions/v1_14_3.rs +++ b/protocol/src/protocol/versions/v1_14_3.rs @@ -65,7 +65,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_14_4.rs b/protocol/src/protocol/versions/v1_14_4.rs index f74d5ee..6e3d924 100644 --- a/protocol/src/protocol/versions/v1_14_4.rs +++ b/protocol/src/protocol/versions/v1_14_4.rs @@ -65,7 +65,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_15.rs b/protocol/src/protocol/versions/v1_15.rs index 9e62f9d..cad4eb8 100644 --- a/protocol/src/protocol/versions/v1_15.rs +++ b/protocol/src/protocol/versions/v1_15.rs @@ -66,7 +66,7 @@ protocol_packet_ids!( 0x07 => Statistics 0x08 => AcknowledgePlayerDigging 0x09 => BlockBreakAnimation - 0x0a => UpdateBlockEntity + 0x0a => UpdateBlockEntity_u8 0x0b => BlockAction 0x0c => BlockChange_VarInt 0x0d => BossBar diff --git a/protocol/src/protocol/versions/v1_16_1.rs b/protocol/src/protocol/versions/v1_16_1.rs index a29f785..9800500 100644 --- a/protocol/src/protocol/versions/v1_16_1.rs +++ b/protocol/src/protocol/versions/v1_16_1.rs @@ -66,7 +66,7 @@ protocol_packet_ids!( 0x06 => Statistics 0x07 => AcknowledgePlayerDigging 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_16_4.rs b/protocol/src/protocol/versions/v1_16_4.rs index 0a47fd7..344b784 100644 --- a/protocol/src/protocol/versions/v1_16_4.rs +++ b/protocol/src/protocol/versions/v1_16_4.rs @@ -67,7 +67,7 @@ protocol_packet_ids!( 0x06 => Statistics 0x07 => AcknowledgePlayerDigging 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_17_1.rs b/protocol/src/protocol/versions/v1_17_1.rs index 837b596..c986cea 100644 --- a/protocol/src/protocol/versions/v1_17_1.rs +++ b/protocol/src/protocol/versions/v1_17_1.rs @@ -68,7 +68,7 @@ protocol_packet_ids!( 0x07 => Statistics 0x08 => AcknowledgePlayerDigging 0x09 => BlockBreakAnimation - 0x0a => UpdateBlockEntity + 0x0a => UpdateBlockEntity_u8 0x0b => BlockAction 0x0c => BlockChange_VarInt 0x0d => BossBar diff --git a/protocol/src/protocol/versions/v1_18_1.rs b/protocol/src/protocol/versions/v1_18_1.rs new file mode 100644 index 0000000..90cc499 --- /dev/null +++ b/protocol/src/protocol/versions/v1_18_1.rs @@ -0,0 +1,191 @@ +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_Filtering + 0x06 => TabComplete + 0x07 => ClickWindowButton + 0x08 => ClickWindow_State + 0x09 => CloseWindow + 0x0a => PluginMessageServerbound + 0x0b => EditBook_Pages + 0x0c => QueryEntityNBT + 0x0d => UseEntity_Sneakflag + 0x0e => GenerateStructure + 0x0f => KeepAliveServerbound_i64 + 0x10 => LockDifficulty + 0x11 => PlayerPosition + 0x12 => PlayerPositionLook + 0x13 => PlayerLook + 0x14 => Player + 0x15 => VehicleMove + 0x16 => SteerBoat + 0x17 => PickItem + 0x18 => CraftRecipeRequest + 0x19 => ClientAbilities_u8 + 0x1a => PlayerDigging + 0x1b => PlayerAction + 0x1c => SteerVehicle + 0x1d => WindowPong + 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 => SculkVibrationSignal + 0x06 => Animation + 0x07 => Statistics + 0x08 => AcknowledgePlayerDigging + 0x09 => BlockBreakAnimation + 0x0a => UpdateBlockEntity_VarInt + 0x0b => BlockAction + 0x0c => BlockChange_VarInt + 0x0d => BossBar + 0x0e => ServerDifficulty_Locked + 0x0f => ServerMessage_Sender + 0x10 => ClearTitles + 0x11 => TabCompleteReply + 0x12 => DeclareCommands + 0x13 => WindowClose + 0x14 => WindowItems_StateCarry + 0x15 => WindowProperty + 0x16 => WindowSetSlot_State + 0x17 => SetCooldown + 0x18 => PluginMessageClientbound + 0x19 => NamedSoundEffect + 0x1a => Disconnect + 0x1b => EntityAction + 0x1c => Explosion_VarInt + 0x1d => ChunkUnload + 0x1e => ChangeGameState + 0x1f => WindowOpenHorse + 0x20 => WorldBorderInit + 0x21 => KeepAliveClientbound_i64 + 0x22 => ChunkData_AndLight + 0x23 => Effect + 0x24 => Particle_f64 + 0x25 => UpdateLight_Arrays + 0x26 => JoinGame_WorldNames_IsHard_SimDist + 0x27 => Maps + 0x28 => TradeList_WithRestock + 0x29 => EntityMove_i16 + 0x2a => EntityLookAndMove_i16 + 0x2b => EntityLook_VarInt + 0x2c => VehicleTeleport + 0x2d => OpenBook + 0x2e => WindowOpen_VarInt + 0x2f => SignEditorOpen + 0x30 => WindowPing + 0x31 => CraftRecipeResponse + 0x32 => PlayerAbilities + 0x33 => CombatEventEnd + 0x34 => CombatEventEnter + 0x35 => CombatEventDeath + 0x36 => PlayerInfo + 0x37 => FacePlayer + 0x38 => TeleportPlayer_WithDismount + 0x39 => UnlockRecipes_WithBlastSmoker + 0x3a => EntityDestroy + 0x3b => EntityRemoveEffect + 0x3c => ResourcePackSend_Prompt + 0x3d => Respawn_NBT + 0x3e => EntityHeadLook + 0x3f => MultiBlockChange_Packed + 0x40 => SelectAdvancementTab + 0x41 => ActionBar + 0x42 => WorldBorderCenter + 0x43 => WorldBorderLerpSize + 0x44 => WorldBorderSize + 0x45 => WorldBorderWarningDelay + 0x46 => WorldBorderWarningReach + 0x47 => Camera + 0x48 => SetCurrentHotbarSlot + 0x49 => UpdateViewPosition + 0x4a => UpdateViewDistance + 0x4b => SpawnPosition_Angle + 0x4c => ScoreboardDisplay + 0x4d => EntityMetadata + 0x4e => EntityAttach + 0x4f => EntityVelocity + 0x50 => EntityEquipment_Array + 0x51 => SetExperience + 0x52 => UpdateHealth + 0x53 => ScoreboardObjective + 0x54 => SetPassengers + 0x55 => Teams_VarInt + 0x56 => UpdateScore + 0x57 => UpdateSimulationDistance + 0x58 => TitleSubtitle + 0x59 => TimeUpdate + 0x5a => Title + 0x5b => TitleTimes + 0x5c => EntitySoundEffect + 0x5d => SoundEffect + 0x5e => StopSound + 0x5f => PlayerListHeaderFooter + 0x60 => NBTQueryResponse + 0x61 => CollectItem + 0x62 => EntityTeleport_f64 + 0x63 => Advancements + 0x64 => EntityProperties_VarIntVarInt + 0x65 => EntityEffect + 0x66 => DeclareRecipes + 0x67 => Tags_Nested + } + } + 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 + } + } +); diff --git a/protocol/src/protocol/versions/v1_8_9.rs b/protocol/src/protocol/versions/v1_8_9.rs index 6cc86f9..4d61379 100644 --- a/protocol/src/protocol/versions/v1_8_9.rs +++ b/protocol/src/protocol/versions/v1_8_9.rs @@ -89,7 +89,7 @@ protocol_packet_ids!( 0x32 => ConfirmTransaction 0x33 => UpdateSign 0x34 => Maps_NoTracking - 0x35 => UpdateBlockEntity + 0x35 => UpdateBlockEntity_u8 0x36 => SignEditorOpen 0x37 => Statistics 0x38 => PlayerInfo diff --git a/protocol/src/protocol/versions/v1_9.rs b/protocol/src/protocol/versions/v1_9.rs index 6f2ebe4..108c232 100644 --- a/protocol/src/protocol/versions/v1_9.rs +++ b/protocol/src/protocol/versions/v1_9.rs @@ -49,7 +49,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/protocol/versions/v1_9_2.rs b/protocol/src/protocol/versions/v1_9_2.rs index 05eb1f6..5dc0adf 100644 --- a/protocol/src/protocol/versions/v1_9_2.rs +++ b/protocol/src/protocol/versions/v1_9_2.rs @@ -49,7 +49,7 @@ protocol_packet_ids!( 0x06 => Animation 0x07 => Statistics 0x08 => BlockBreakAnimation - 0x09 => UpdateBlockEntity + 0x09 => UpdateBlockEntity_u8 0x0a => BlockAction 0x0b => BlockChange_VarInt 0x0c => BossBar diff --git a/protocol/src/types/bit/map.rs b/protocol/src/types/bit/map.rs index 3af1fd4..1c743ec 100644 --- a/protocol/src/types/bit/map.rs +++ b/protocol/src/types/bit/map.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[derive(Debug)] pub struct Map { bits: Vec, pub bit_size: usize, @@ -63,11 +64,20 @@ impl Map { } pub fn from_raw(bits: Vec, size: usize, padded: bool) -> Map { - Map { - length: (bits.len() * 64 + (size - 1)) / size, - bit_size: size, - bits, - padded, + if size == 0 { + Map { + length: 0, + bit_size: size, + bits, + padded, + } + } else { + Map { + length: (bits.len() * 64 + (size - 1)) / size, + bit_size: size, + bits, + padded, + } } } @@ -80,6 +90,7 @@ impl Map { } fn get_bit_offset(&self, i: usize) -> usize { + assert!(self.length != 0); let padding = if self.padded { i / (64 / self.bit_size) * (64 % self.bit_size) } else { diff --git a/src/server/mod.rs b/src/server/mod.rs index 1851e9b..54731bc 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -581,6 +581,7 @@ impl Server { self pck { PluginMessageClientbound_i16 => on_plugin_message_clientbound_i16, PluginMessageClientbound => on_plugin_message_clientbound_1, + JoinGame_WorldNames_IsHard_SimDist => on_game_join_worldnames_ishard_simdist, JoinGame_WorldNames_IsHard => on_game_join_worldnames_ishard, JoinGame_WorldNames => on_game_join_worldnames, JoinGame_HashedSeed_Respawn => on_game_join_hashedseed_respawn, @@ -595,6 +596,7 @@ impl Server { KeepAliveClientbound_i64 => on_keep_alive_i64, KeepAliveClientbound_VarInt => on_keep_alive_varint, KeepAliveClientbound_i32 => on_keep_alive_i32, + ChunkData_AndLight => on_chunk_data_and_light, ChunkData_Biomes3D_Bitmasks => on_chunk_data_biomes3d_bitmasks, ChunkData_Biomes3D_VarInt => on_chunk_data_biomes3d_varint, ChunkData_Biomes3D_bool => on_chunk_data_biomes3d_bool, @@ -618,7 +620,8 @@ impl Server { TeleportPlayer_OnGround => on_teleport_player_onground, TimeUpdate => on_time_update, ChangeGameState => on_game_state_change, - UpdateBlockEntity => on_block_entity_update, + UpdateBlockEntity_VarInt => on_block_entity_update_varint, + UpdateBlockEntity_u8 => on_block_entity_update_u8, UpdateBlockEntity_Data => on_block_entity_update_data, UpdateSign => on_sign_update, UpdateSign_u16 => on_sign_update_u16, @@ -1055,10 +1058,19 @@ impl Server { .write_plugin_message(channel, data); // TODO handle errors } + fn on_game_join_worldnames_ishard_simdist( + &mut self, + join: packet::play::clientbound::JoinGame_WorldNames_IsHard_SimDist, + ) { + self.world.load_dimension_type(join.dimension); + self.on_game_join(join.gamemode, join.entity_id) + } + fn on_game_join_worldnames_ishard( &mut self, join: packet::play::clientbound::JoinGame_WorldNames_IsHard, ) { + self.world.load_dimension_type(join.dimension); self.on_game_join(join.gamemode, join.entity_id) } @@ -1677,9 +1689,27 @@ impl Server { } } - fn on_block_entity_update( + fn on_block_entity_update_varint( &mut self, - block_update: packet::play::clientbound::UpdateBlockEntity, + block_update: packet::play::clientbound::UpdateBlockEntity_VarInt, + ) { + self.on_block_entity_update_u8(packet::play::clientbound::UpdateBlockEntity_u8 { + location: block_update.location, + action: block_update.action.0 as u8, + nbt: block_update.nbt, + }); + } + + fn on_block_entity_update_data( + &mut self, + _block_update: packet::play::clientbound::UpdateBlockEntity_Data, + ) { + // TODO: handle UpdateBlockEntity_Data for 1.7, decompress gzipped_nbt + } + + fn on_block_entity_update_u8( + &mut self, + block_update: packet::play::clientbound::UpdateBlockEntity_u8, ) { match block_update.nbt { None => { @@ -1736,13 +1766,6 @@ impl Server { } } - fn on_block_entity_update_data( - &mut self, - _block_update: packet::play::clientbound::UpdateBlockEntity_Data, - ) { - // TODO: handle UpdateBlockEntity_Data for 1.7, decompress gzipped_nbt - } - fn on_sign_update(&mut self, mut update_sign: packet::play::clientbound::UpdateSign) { format::convert_legacy(&mut update_sign.line1); format::convert_legacy(&mut update_sign.line2); @@ -1931,7 +1954,7 @@ impl Server { // Not something we care about, so break the loop _ => continue, } - self.on_block_entity_update(packet::play::clientbound::UpdateBlockEntity { + self.on_block_entity_update_u8(packet::play::clientbound::UpdateBlockEntity_u8 { location: Position::new(x, y, z), action, nbt: Some(block_entity.clone()), @@ -1945,6 +1968,24 @@ impl Server { } } + fn on_chunk_data_and_light( + &mut self, + chunk_data: packet::play::clientbound::ChunkData_AndLight, + ) { + self.world + .load_chunk117( + chunk_data.chunk_x, + chunk_data.chunk_z, + true, + 0xffff, // world height/16 (256/16 = 16) bits + 16, // TODO: get all bitmasks + chunk_data.data.data, + ) + .unwrap(); + //self.load_block_entities(chunk_data.block_entities.data); // TODO: load entities + // TODO: update light + } + fn on_chunk_data_biomes3d_bitmasks( &mut self, chunk_data: packet::play::clientbound::ChunkData_Biomes3D_Bitmasks, diff --git a/src/world/mod.rs b/src/world/mod.rs index 71e348e..e51aff6 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -25,6 +25,7 @@ use crate::types::hash::FNVHash; use crate::types::{bit, nibble}; use cgmath::prelude::*; use flate2::read::ZlibDecoder; +use log::info; use std::cmp::Ordering; use std::collections::HashMap; use std::collections::VecDeque; @@ -38,6 +39,7 @@ mod storage; #[derive(Default)] pub struct World { chunks: HashMap>, + min_y: i32, render_list: Vec<(i32, i32, i32)>, @@ -1005,6 +1007,17 @@ impl World { self.load_chunk19_to_117(false, x, z, new, mask, num_sections, data) } + pub fn load_dimension_type(&mut self, dimension_tags: Option) { + if let Some(crate::nbt::NamedTag(_, crate::nbt::Tag::Compound(tags))) = dimension_tags { + info!("Dimension type: {:?}", tags); + + if let Some(crate::nbt::Tag::Int(min_y)) = tags.get("min_y") { + self.min_y = *min_y; + } + // TODO: More tags https://wiki.vg/Protocol#Login_.28play.29 + } + } + #[allow(clippy::or_fun_call)] fn load_chunk19_to_117( &mut self, @@ -1031,10 +1044,48 @@ impl World { } let chunk = self.chunks.get_mut(&cpos).unwrap(); - for i in 0..num_sections { + for i1 in 0..num_sections { + let i: i32 = (i1 as i32) + (self.min_y >> 4); + if i < 0 { + // TODO: support y<0 in the world (needs shifting in all section access) + let block_count = data.read_u16::()?; + let bit_size = data.read_u8()?; + let single_value = Some(VarInt::read_from(&mut data)?.0); + if bit_size != 0 || single_value != Some(0) || block_count != 0 { + panic!("TODO: support chunk data y<0 non-air (bit_size {}, single_value {:?}, block_count {})", bit_size, single_value, block_count); + } + let _bits = LenPrefixed::::read_from(&mut data)?.data; + + // biome + let _bit_size = data.read_u8()?; + if _bit_size == 0 { + let _single_value = VarInt::read_from(&mut data)?.0; + } else { + if bit_size >= 4 { + panic!( + "TODO: handle direct palettes, bit_size {} >= 4 for biomes", + bit_size + ); + } + + let count = VarInt::read_from(&mut data)?.0; + for _i in 0..count { + let _id = VarInt::read_from(&mut data)?.0; + } + } + let _bits = LenPrefixed::::read_from(&mut data)?.data; + + continue; + } + let i = i as usize; + if chunk.sections[i].is_none() { let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none()); fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0; + if self.protocol_version >= 757 { + // TODO: fix conditionalizing fill sky on 1.18+ + fill_sky = true; + } if !fill_sky || mask & (1 << i) != 0 { chunk.sections[i] = Some(Section::new(i as u8, fill_sky)); } @@ -1047,16 +1098,30 @@ impl World { if self.protocol_version >= 451 { let _block_count = data.read_u16::()?; - // TODO: use block_count + // TODO: use block_count, "The client will keep count of the blocks as they are + // broken and placed, and, if the block count reaches 0, the whole chunk + // section is not rendered, even if it still has blocks." per https://wiki.vg/Chunk_Format#Data_structure } let mut bit_size = data.read_u8()?; let mut mappings: HashMap> = HashMap::with_hasher(BuildHasherDefault::default()); + let mut single_value: Option = None; if bit_size == 0 { - bit_size = 13; + if self.protocol_version >= 757 { + // Single-valued palette + single_value = Some(VarInt::read_from(&mut data)?.0.try_into().unwrap()); + } else { + bit_size = 13; + } } else { let count = VarInt::read_from(&mut data)?.0; + if bit_size >= 9 { + panic!( + "TODO: handle direct palettes, bit_size {} >= 9 for block states", + bit_size + ); + } for i in 0..count { let id = VarInt::read_from(&mut data)?.0; let bl = self @@ -1065,13 +1130,17 @@ impl World { mappings.insert(i as usize, bl); } } + if bit_size > 16 { + // https://wiki.vg/Chunk_Format#Data_structure "This increase can go up to 16 bits per block"... + panic!("load_chunk19_to_117: bit_size={:?} > 16", bit_size); + } let bits = LenPrefixed::::read_from(&mut data)?.data; 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); + let id = single_value.unwrap_or_else(|| m.get(bi)); section.blocks.set( bi, mappings @@ -1101,7 +1170,31 @@ impl World { } } - if self.protocol_version >= 451 { + if self.protocol_version >= 757 { + // Biomes palette TODO: refactor with block states, "palette container" + let _bit_size = data.read_u8()?; + if _bit_size == 0 { + // Single-valued palette + let _single_value = VarInt::read_from(&mut data)?.0; + } else { + if bit_size >= 4 { + panic!( + "TODO: handle direct palettes, bit_size {} >= 4 for biomes", + bit_size + ); + } + + let count = VarInt::read_from(&mut data)?.0; + for _i in 0..count { + let _id = VarInt::read_from(&mut data)?.0; + //let bl = self + // .id_map + // .by_vanilla_id(id as usize, &self.modded_block_ids); + //mappings.insert(i as usize, bl); + } + } + let _bits = LenPrefixed::::read_from(&mut data)?.data; + } else if self.protocol_version >= 451 { // Skylight in update skylight packet for 1.14+ } else { data.read_exact(&mut section.block_light.data)?;