2023-07-24 00:50:20 -04:00
|
|
|
use std::io::{Write, Read};
|
|
|
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
use crate::{ser::{Serializable, Deserializable}, varint::VarInt};
|
|
|
|
|
|
|
|
use super::{ServerPacket, ClientPacket, Protocol, ProtocolState, common::COMMON};
|
|
|
|
|
|
|
|
pub const VERSION: i32 = 763;
|
|
|
|
|
|
|
|
pub const PROTOCOL: Protocol = Protocol {
|
|
|
|
name: "1.20.1",
|
|
|
|
version: VERSION,
|
|
|
|
encode,
|
|
|
|
decode,
|
|
|
|
};
|
|
|
|
|
|
|
|
fn encode(mut w: Box<&mut dyn Write>, state: ProtocolState, ev: ServerPacket) -> anyhow::Result<()> {
|
|
|
|
match ev {
|
|
|
|
ServerPacket::LoginSuccess { name, uuid } => {
|
|
|
|
VarInt(0x02).serialize(&mut w)?;
|
|
|
|
uuid.serialize(&mut w)?;
|
|
|
|
name.serialize(&mut w)?;
|
|
|
|
// number of properties (0)
|
|
|
|
VarInt(0x00).serialize(&mut w)?;
|
|
|
|
},
|
|
|
|
ServerPacket::JoinGame { eid, gamemode, hardcode } => {
|
|
|
|
VarInt(0x28).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!("registry.nbt").serialize(&mut w)?; // registry codec
|
|
|
|
"minecraft:the_end".serialize(&mut w)?; // dimension type
|
|
|
|
"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
|
|
|
|
VarInt(0).serialize(&mut w)?; // sim 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
|
|
|
|
false.serialize(&mut w)?; // has death location
|
|
|
|
VarInt(1).serialize(&mut w)?; // portal cooldown
|
|
|
|
},
|
|
|
|
ServerPacket::KeepAlive(data) => {
|
|
|
|
VarInt(0x23).serialize(&mut w)?;
|
|
|
|
data.serialize(&mut w)?;
|
|
|
|
},
|
|
|
|
ServerPacket::PlayDisconnect(msg) => {
|
|
|
|
VarInt(0x1A).serialize(&mut w)?;
|
|
|
|
msg.serialize(&mut w)?;
|
|
|
|
},
|
2023-07-26 00:53:51 -04:00
|
|
|
ServerPacket::PluginMessage { channel, data } => {
|
2023-07-24 00:50:20 -04:00
|
|
|
VarInt(0x17).serialize(&mut w)?;
|
|
|
|
channel.serialize(&mut w)?;
|
2023-07-26 00:53:51 -04:00
|
|
|
w.write_all(&data)?;
|
2023-07-24 00:50:20 -04:00
|
|
|
},
|
|
|
|
ServerPacket::ChunkData { x, z } => {
|
|
|
|
VarInt(0x24).serialize(&mut w)?;
|
|
|
|
// chunk x
|
|
|
|
x.serialize(&mut w)?;
|
|
|
|
// chunk z
|
|
|
|
z.serialize(&mut w)?;
|
|
|
|
// heightmap
|
|
|
|
let hmdata = [0i64; 37];
|
|
|
|
let mut heightmap = nbt::Blob::new();
|
|
|
|
heightmap.insert("MOTION_BLOCKING", hmdata.as_ref()).unwrap();
|
|
|
|
heightmap.serialize(&mut w)?;
|
|
|
|
// chunk data
|
|
|
|
let mut chunk_data: Vec<u8> = Vec::new();
|
|
|
|
for _ in 0..(384 / 16) {
|
|
|
|
// number of non-air blocks
|
|
|
|
(0i16).serialize(&mut chunk_data)?;
|
|
|
|
// block states
|
|
|
|
(0u8).serialize(&mut chunk_data)?;
|
|
|
|
VarInt(0).serialize(&mut chunk_data)?;
|
|
|
|
VarInt(0).serialize(&mut chunk_data)?;
|
|
|
|
// biomes
|
|
|
|
(0u8).serialize(&mut chunk_data)?;
|
|
|
|
VarInt(0).serialize(&mut chunk_data)?;
|
|
|
|
VarInt(0).serialize(&mut chunk_data)?;
|
|
|
|
}
|
|
|
|
VarInt(chunk_data.len() as i32).serialize(&mut w)?;
|
|
|
|
w.write_all(&chunk_data)?;
|
|
|
|
// block entities
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
// light masks
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
// sky light array len
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
// block light array len
|
|
|
|
VarInt(0).serialize(&mut w)?;
|
|
|
|
},
|
|
|
|
ServerPacket::SetDefaultSpawn { pos, angle } => {
|
|
|
|
VarInt(0x50).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<Option<ClientPacket>> {
|
|
|
|
type Ps = ProtocolState;
|
|
|
|
match (state, id) {
|
|
|
|
(Ps::Login, 0x00) => {
|
|
|
|
let name = String::deserialize(&mut r)?;
|
|
|
|
let has_uuid = bool::deserialize(&mut r)?;
|
|
|
|
let uuid = if has_uuid {
|
|
|
|
Some(Uuid::deserialize(&mut r)?)
|
|
|
|
} else { None };
|
|
|
|
Ok(Some(ClientPacket::LoginStart { name, uuid }))
|
|
|
|
}
|
|
|
|
(Ps::Login, 0x01 | 0x02) => Ok(None), // unsupported
|
|
|
|
(Ps::Play, 0x0D) => {
|
|
|
|
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, 0x12) => {
|
|
|
|
let data = i64::deserialize(&mut r)?;
|
|
|
|
Ok(Some(ClientPacket::KeepAlive(data)))
|
|
|
|
}
|
|
|
|
(Ps::Play, 0x14 | 0x15 | 0x16) => Ok(None), // position & rotation
|
|
|
|
_ => (COMMON.decode)(r, state, len, id)
|
|
|
|
}
|
|
|
|
}
|