use std::io::{Write, Read}; use log::trace; use crate::{ser::{Serializable, Deserializable}, varint::VarInt}; use super::{ServerPacket, ClientPacket, Protocol, ProtocolState, common::COMMON}; pub const NAME: &str = "1.13.2"; pub const VERSION: i32 = 404; 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.to_string().serialize(&mut w)?; name.serialize(&mut w)?; }, ServerPacket::ChatMessage(msg, _) => { VarInt(0x0E).serialize(&mut w)?; msg.serialize(&mut w)?; 0u8.serialize(&mut w)?; // chat }, ServerPacket::SystemMessage(msg, overlay) => { VarInt(0x0E).serialize(&mut w)?; msg.serialize(&mut w)?; if overlay { 2u8 } else { 1u8 } // system or overlay .serialize(&mut w)?; }, ServerPacket::PluginMessage { channel, data } => { VarInt(0x19).serialize(&mut w)?; channel.serialize(&mut w)?; w.write_all(&data)?; }, ServerPacket::PlayDisconnect(msg) => { VarInt(0x1B).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)?; // full chunk true.serialize(&mut w)?; // bit mask VarInt(0).serialize(&mut w)?; // chunk data size and chunk data (biomes) VarInt(256*4).serialize(&mut w)?; [127i32; 256].serialize(&mut w)?; // block entities VarInt(0).serialize(&mut w)?; }, ServerPacket::JoinGame { eid, gamemode, hardcode } => { VarInt(0x25).serialize(&mut w)?; eid.serialize(&mut w)?; (gamemode | (hardcode as u8) << 3).serialize(&mut w)?; 1i32.serialize(&mut w)?; // end dimension 2u8.serialize(&mut w)?; // difficulty 255u8.serialize(&mut w)?; // max players "default".serialize(&mut w)?; // level type false.serialize(&mut w)?; // reduce debug info } ServerPacket::PositionAndLook { pos, look, flags } => { VarInt(0x32).serialize(&mut w)?; pos.serialize(&mut w)?; look.serialize(&mut w)?; flags.serialize(&mut w)?; VarInt(0).serialize(&mut w)?; // teleport id } ServerPacket::SetDefaultSpawn { pos, angle: _ } => { VarInt(0x49).serialize(&mut w)?; pos.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, 0x02) => { 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, 0x0E) => { let data = i64::deserialize(&mut r)?; Ok(Some(ClientPacket::KeepAlive(data))) } (Ps::Play, 0x10 | 0x11 | 0x12) => Ok(None), // position & rotation _ => (COMMON.decode)(r, state, len, id) } }