use std::io::{Write, Read}; use log::trace; use crate::{ser::{Serializable, Deserializable}, varint::VarInt, command::Commands}; use super::{ServerPacket, ClientPacket, Protocol, ProtocolState, common::COMMON}; pub const NAME: &str = "1.17.1"; pub const VERSION: i32 = 756; pub const PROTOCOL: Protocol = Protocol { name: NAME, version: VERSION, encode, decode, }; fn encode(mut w: Box<&mut dyn Write>, state: ProtocolState, ev: ServerPacket) -> anyhow::Result<()> { trace!("{NAME} encoding {ev:?}"); match ev { ServerPacket::LoginSuccess { name, uuid } => { VarInt(0x02).serialize(&mut w)?; uuid.serialize(&mut w)?; name.serialize(&mut w)?; }, ServerPacket::ChatMessage(msg, _) => { VarInt(0x0F).serialize(&mut w)?; msg.serialize(&mut w)?; 0u8.serialize(&mut w)?; // chat 0u128.serialize(&mut w)?; // null uuid }, ServerPacket::SystemMessage(msg, overlay) => { VarInt(0x0F).serialize(&mut w)?; msg.serialize(&mut w)?; if overlay { 2u8 } else { 1u8 } // system or overlay .serialize(&mut w)?; 0u128.serialize(&mut w)?; // null uuid }, ServerPacket::CommandData(commands) => { VarInt(0x12).serialize(&mut w)?; VarInt(commands.len()).serialize(&mut w)?; commands.serialize(&mut w, false)?; VarInt(Commands::root()).serialize(&mut w)?; }, ServerPacket::PluginMessage { channel, data } => { VarInt(0x18).serialize(&mut w)?; channel.serialize(&mut w)?; w.write_all(&data)?; }, ServerPacket::PlayDisconnect(msg) => { VarInt(0x1A).serialize(&mut w)?; msg.serialize(&mut w)?; }, ServerPacket::KeepAlive(data) => { VarInt(0x21).serialize(&mut w)?; data.serialize(&mut w)?; }, ServerPacket::ChunkData { x, z } => { VarInt(0x22).serialize(&mut w)?; // chunk x x.serialize(&mut w)?; // chunk z z.serialize(&mut w)?; // bit mask VarInt(0).serialize(&mut w)?; // heightmap include_bytes!("../resources/heightmap.nbt").serialize(&mut w)?; // biomes VarInt(1024).serialize(&mut w)?; [VarInt(127); 1024].serialize(&mut w)?; // chunk data size and chunk data VarInt(0).serialize(&mut w)?; // block entities VarInt(0).serialize(&mut w)?; }, ServerPacket::JoinGame { eid, gamemode, hardcode } => { VarInt(0x26).serialize(&mut w)?; eid.serialize(&mut w)?; hardcode.serialize(&mut w)?; gamemode.serialize(&mut w)?; (-1i8).serialize(&mut w)?; // prev gamemode undefined VarInt(1).serialize(&mut w)?; // dimension count "qc:world".serialize(&mut w)?; // register one dimension include_bytes!("../resources/dimcodec_1.17.1.nbt").serialize(&mut w)?; // dimension codec include_bytes!("../resources/dimension_1.17.1.nbt").serialize(&mut w)?; // dimension data "qc:world".serialize(&mut w)?; // dimension name 0i64.serialize(&mut w)?; // seed VarInt(65535).serialize(&mut w)?; // max players VarInt(8).serialize(&mut w)?; // view dist false.serialize(&mut w)?; // reduce debug info false.serialize(&mut w)?; // respawn screen false.serialize(&mut w)?; // is debug false.serialize(&mut w)?; // is flat }, ServerPacket::PositionAndLook { pos, look, flags } => { VarInt(0x38).serialize(&mut w)?; pos.serialize(&mut w)?; look.serialize(&mut w)?; flags.serialize(&mut w)?; VarInt(0).serialize(&mut w)?; // teleport id false.serialize(&mut w)?; // dismount } ServerPacket::SetDefaultSpawn { pos, angle } => { VarInt(0x4B).serialize(&mut w)?; pos.serialize(&mut w)?; angle.serialize(&mut w)?; }, _ => { (COMMON.encode)(w, state, ev)?; } } Ok(()) } fn decode(mut r: Box<&mut dyn Read>, state: ProtocolState, len: i32, id: i32) -> anyhow::Result> { trace!("{NAME} decoding {state:?} {id}"); type Ps = ProtocolState; match (state, id) { (Ps::Login, 0x00) => { let name = String::deserialize(&mut r)?; Ok(Some(ClientPacket::LoginStart { name, uuid: None })) } (Ps::Login, 0x01 | 0x02) => Ok(None), // unsupported (Ps::Play, 0x03) => { let mut msg = String::deserialize(&mut r)?; if msg.starts_with('/') { msg.remove(0); Ok(Some(ClientPacket::Command(msg))) } else { Ok(Some(ClientPacket::ChatMessage(msg))) } }, (Ps::Play, 0x0A) => { let channel = String::deserialize(&mut r)?; let mut data = Vec::new(); r.read_to_end(&mut data)?; Ok(Some(ClientPacket::PluginMessage { channel, data })) } (Ps::Play, 0x0F) => { let data = i64::deserialize(&mut r)?; Ok(Some(ClientPacket::KeepAlive(data))) } (Ps::Play, 0x11 | 0x12 | 0x13) => Ok(None), // position & rotation _ => (COMMON.decode)(r, state, len, id) } }